2009-12-15 70 views
16

問候, 我正在C#中開發一些應用程序。目前,我正在處理線程問題,我有一個問題,我腦海裏想着。 Invoke和BeginInvoke有什麼區別? 我讀了一些線索,我在這裏找到一些有用的信息:hereInvoke和BeginInvoke

然而就是在下面的代碼中調用和BeginInvoke的區別:

private void ProcessRoutine() 
{ 
    for (int nValue = StartFrom; nValue <= EndTo; nValue++) 
    { 
     this.Invoke(this.MyDelegate, nValue); 
     //this.BeginInvoke(this.MyDelegate, nValue); 
    } 
    MessageBox.Show("Counting complete!"); 
} 
private void MessageHandler(int progress) 
{ 
    lblStatus.Text = lblStatus.Text = "Processing item: " + progress.ToString(); 
    progressBar1.Value = progress; 
} 

其中MyDelegate是的MessageHandler函數的引用。

我注意到使用BeginInvoke lblStatus.Text不刷新使用Invoke刷新標籤的地方。 另外我知道Invoke等待它的執行完成。 我感興趣的最重要的案例是爲什麼在這種情況下刷新標籤文本有所不同。

回答

8

With Invoke方法得到執行並且應用程序等待它完成。

使用BeginInvoke方法將被異步調用,並且在BeginInvoke中引用的方法被執行時,應用程序將繼續執行。

使用BeginInvoke,您需要調用EndInvoke來獲取使用BeginIvnoke執行的方法的結果。

您不應該更新BeginXXX方法中的GUI組件,因爲它們在GUI線程的另一個線程中運行,與您的Invoke方法相反。您不能在GUI線程的不同線程中訪問GUI組件。

希望這會有所幫助!

+12

調用的BeginInvoke並不意味着它不會在用戶界面上執行線。這意味着它在與「this」關聯的線程上被異步調用,這可能是UI線程。 – 2009-12-15 19:50:20

+0

所以如果它不在另一個線程中,它是如何工作的呢? – 2009-12-15 20:18:52

+8

從MSDN:「在創建控件的底層句柄的線程上異步執行指定的委託」。因此,如果從UI線程調用它,它將被放置在一個隊列中,並在UI線程閒置時執行。這將在當前執行的方法返回後執行。 – 2009-12-24 14:42:18

1

BeginInvoke在另一個線程上執行方法體,並允許當前線程繼續。如果您試圖直接從另一個線程更新控件屬性,它將引發異常。

+1

是的,我知道,但爲什麼用我的調用標籤文本被刷新,而且使用的BeginInvoke它不是 – 2009-12-15 19:45:31

+0

@Niao看到我的回答的第二句 – 2009-12-15 20:16:50

0

這基本上歸結爲是否要控制更新同步或異步。這完全取決於你的具體情況。

18

首先,從你的鏈接:

  • Control.Invoke:執行UI線程,但調用線程繼續之前等待完成。
  • Control.BeginInvoke:在異步UI線程上執行,並且調用線程不會等待完成。

,並從MSDN:

的BeginInvoke異步執行,控制的基礎句柄創建線程上執行指定的委託。

概括起來講,BeginInvoke是異步。當從UI線程調用BeginInvoke時,請求將與UI線程並行執行。這意味着它可能不會執行,直到當前執行的方法返回。因此,在這種情況下,文本框將永遠不會更新,因爲for循環不會中斷,因爲調用線程不會等待此事件在繼續之前完成。

或者,Invoke同步。文本框將被更新,因爲調用線程將在繼續執行之前等待調用完成。

+2

一個小問題 - 當方法返回時它不會被執行,它是作爲一個火災而忘了 - 它被髮射到COM/winapi ether – 2010-02-12 22:31:48

+0

感謝您的反饋;我剛剛更新了我的答案。 – 2010-02-15 01:37:33

5

Control.BeginInvoke不能在另一個線程(或線程池)上工作,這是一個delegate.BeginInvoke。 MSDN的一個班輪說:

執行指定委託 異步線程上的 控制的基礎句柄 創建上。

然而Control.BeginInvoke簡單的使用PostMessage和回報 - 沒有CLR創建Thread

PostMessage函數放置 (個)在與該 創建指定的窗口和 返回而不等待線程 處理消息線程相關聯的消息隊列 的消息。

This article總結是否使用InvokeBeginInvoke相當不錯:

要使用哪個函數,你問。它 真的取決於您的要求。如果 在繼續進行之前,您希望您的UI更新完成 ,則使用Invoke。如果 沒有這樣的要求,我想 建議使用BeginInvoke,因爲它使 線程調用它看起來 「更快」。儘管如此,還是有一些需要BeginInvoke的疑難雜症 。

  • 如果通過BeginInvoke的調用函數訪問共享狀態 (狀態UI線程 和其他線程之間共享的),則在 麻煩。在您調用 BeginInvoke和包裝的 函數實際執行的時間之間,狀態可能會更改 ,從而導致 很難找到計時問題。
  • 如果您將參考參數傳遞給通過 BeginInvoke調用的函數,則必須確保 在函數完成之前沒有其他人修改傳遞的 對象。 通常,人們在將其傳遞給BeginInvoke, 之前先克隆對象 ,這樣可以完全避免該問題。
相關問題