2008-09-30 100 views
1

我試圖讓我的多線程理解鎖定。我盡我所能教導自己,但其中一些問題需要澄清。另一個鎖定問題

我已經通過一段代碼嘗試了三次迭代。

在這段代碼,需要鎖定的唯一事情是this.managerThreadPriority。

首先,簡單的程序方法,用簡約鎖定。

var managerThread = new Thread 
(
    new ThreadStart(this.ManagerThreadEntryPoint) 
); 

lock (this.locker) 
{ 
    managerThread.Priority = this.managerThreadPriority; 
} 

managerThread.Name = string.Format("Manager Thread ({0})", managerThread.GetHashCode()); 

managerThread.Start(); 

下,一個單獨的語句來創建和啓動一個新的線程,但似乎鎖被作用域太大,包括線程的創建和啓動。編譯器不會奇蹟般地知道在使用this.managerThreadPriority之後鎖可以被釋放。

這種天真的鎖定應該避免,我會假設。

lock (this.locker) 
{ 
    new Thread 
    (
     new ThreadStart(this.ManagerThreadEntryPoint) 
    ) 
    { 
     Priority = this.managerThreadPriority, 
     Name = string.Format("Manager Thread ({0})", GetHashCode()) 
    } 
    .Start(); 
} 

最後,創建和啓動一個新線程的單個語句,只在共享字段周圍「嵌入」鎖。

new Thread 
(
    new ThreadStart(this.ManagerThreadEntryPoint) 
) 
{ 
    Priority = new Func<ThreadPriorty>(() => 
    { 
     lock (this.locker) 
     { 
      return this.managerThreadPriority; 
     } 
    })(), 

    Name = string.Format("Manager Thread ({0})", GetHashCode()) 
} 
.Start(); 

注意關於鎖定語句範圍的評論?例如,如果我需要使用if語句中的字段並且該字段需要被鎖定,我是否應該避免鎖定整個if語句?例如。

bool isDumb; 

lock (this.locker) isDumb = this.FieldAccessibleByMultipleThreads; 

if (isDumb) ... 

VS.

lock (this.locker) 
{ 
    if (this.FieldAccessibleByMultipleThreads) ... 
} 

回答

3

1)之前,你甚至開始另一個線程,你不必擔心共享訪問它。

2)是的,你應該鎖定全部訪問共享可變數據。 (如果這是不可改變的,因此不需要鎖定。)

3)不要使用GetHashCode()方法來表示線程ID。使用Thread.ManagedThreadId。我知道,有推薦Thread.GetHashCode()的書 - 但看看文檔。

0

在開始任何線程之前,沒有必要鎖定任何東西。

如果你只是要讀取一個變量,那麼也不需要鎖。當你讀寫混合時,你需要使用互斥鎖和類似的鎖,並且你需要鎖定讀和寫線程。

+0

即使您只在一個線程中讀取並在另一個線程中寫入,仍然需要鎖定讀取線程 - 否則不能保證您將看到來自其他線程的新寫入的數據。 – 2008-09-30 22:00:56

3

護理約鎖定報表的範圍界定有何評論?例如,如果我 需要使用if語句中的字段並且該字段需要鎖定,我應該避免鎖定整個if語句嗎?

一般來說,它的範圍應該是需要資源被守護的代碼部分,並且不能超過這個範圍。這可以讓其他線程儘快使用它。

它取決於你所鎖定的資源是否具有保持一致性,抑或是沒有直接關係的其他任何一個獨立的資源更大的圖片的一部分。

如果您有相互關聯的零件需要全部以同步方式進行更改,那麼整套零件需要在整個過程期間鎖定。 如果你有一個獨立的單一項目與其他任何東西沒有耦合,那麼只有一個項目需要被鎖定足夠長的時間,以便部分過程訪問它。

另一種說法是是否保護對資源的同步或異步訪問?

同步訪問通常需要保持較長的時間,因爲它關心資源所屬的更大圖片。它必須保持與相關資源的一致性。在這種情況下,如果你想防止中斷,直到全部處理完畢,你可能會很好地包裝整個for循環。

異步訪問應儘可能簡短地保留它。因此,更合適的鎖定位置將放在代碼的部分內部,例如for循環或if語句中,以便在處理其他代碼之前立即釋放單個元素。


除了這兩個考慮因素之外,我還會再增加一個。 避免嵌套涉及兩個不同鎖定對象的鎖。我從經驗中瞭解到,它可能是死鎖的來源,特別是如果代碼的其他部分使用它們。如果這兩個對象是需要一直視爲一個整體的組的一部分,則應該重構此類嵌套。