2011-09-28 27 views
2

我正在研究一個多線程應用程序,它需要更新Winforms控件(DataGridView)。爲了防止同一共享資源的多個訪問,我開始了下面的鎖結構:使用Control.Invoke()代替鎖定(控制)

if (DGV.Columns.Count >= DesiredColumnCount) return; 
lock(DGV) 
{ 
    while (DGV.Columns.Count < DesiredColumnCount) 
    { 
     DGV.Columns.Add(newColumn); 
    } 
} 

我後來意識到,由於DGV是在UI線程上創建的,它需要.Invoke()「d 。這將代碼更改爲:

​​

我的問題是:這不是多餘的嗎? lock將阻止工作線程,直到它具有對DGV的獨佔訪問權限,並且Invoke()將阻塞工作線程,直到UI線程可以接收調用請求並執行代碼。我不能只通過使用Invoke()

(這是最主要的問題。當然,如果在上面的代碼中任何其他多線程的罪過,請評論)

+0

你對「工作者線程」有什麼用? –

+0

你不應該阻止UI線程。這適用於鎖定以及Control.Invoke。您應該擺脫鎖定並將Invoke更改爲BeginInvoke。 –

+0

@PeterRitchie我不記得究竟是什麼啓動了線程。它可能是'new Thread().Start()'或'System.Threading.Timer.Elapsed'。這段代碼不會阻塞UI線程,它會阻止工作者。 BeginInvoke不能盲目取代Invoke,因爲它不會阻塞調用者:我需要對調用進行排隊,以確保它們不會以錯誤的順序執行而跳過彼此。這可以通過減少阻塞工作線程所花費的時間來提高性能,但這是迄今爲止的一箇舊項目。 – Nathan

回答

3

這是一個有點多餘,在Invoke通話將「派遣」的operpation到UI線。隨後的每個Invoke調用都將以串行方式進行調度,因此實際上不需要進行任何鎖定。

您可以考慮使用BeginInvoke而不是Invoke命令來防止工作線程阻塞,但同樣這將「串行」完成,因此不需要擔心鎖定。

+0

感謝帖子,但我很困惑。 Skeet先生在(http://stackoverflow.com/questions/229554/whats-the-difference-between-invoke-and-begininvoke)中說,Control.Invoke在UI線程上執行並等待完成。 – Nathan

+0

是的,他在談論BeginInvoke()。沒關係,你不需要任何一個鎖。所有代碼都在同一個線程上運行,因此不需要保護數據。 –

+2

不僅是多餘的鎖,它是一個等待發生的死鎖。如果在調用'Invoke'期間調用的某些代碼試圖獲取該鎖,則由於線程持有該鎖,等待在該UI線程上完成'Invoke'並且UI線程正在等待獲得鎖定。 –