2011-09-19 22 views
2

我有一個代碼塊,必須在與窗口相同的線程中執行。所以我想爲這個塊調用Form.Invoke。但是包含代碼塊的方法可以從不同的線程中調用,其中之一就是窗口線程。當已經在正確的線程中Form.Invoke呢?

所以我的問題是:是否可以使用Form.Invoke,但該方法可能已被調用在正確的線程?或者這是否會產生開銷甚至是可能的錯誤來源?

+1

它工作正常,但有一定的開銷。我主頻它在每次通話10微秒,每次通話0.3微秒,如果你使用InvokeRequired。 –

+0

@Hans爲什麼會是這樣?我必須承認我覺得很驚訝。我認爲Invoke在GUI線程上調用時有效地執行了相同的優化。 –

+1

@大衛 - 它僅測試*將委託給invoke隊列後,線程*。有必要的是,仍然需要正確定購電話。 –

回答

3

是的,可以從擁有句柄的線程調用Invoke

絕大多數代碼示例建議您在決定是否調用Invoke之前應測試InvokeRequired

if (control.InvokeRequired) 
{ 
    control.Invoke(action); 
} 
else 
{  
    action(); 
} 

然而,這導致了相當混亂的代碼,如果你必須支持非GUI線程調用,那麼我建議你只需在所有的情況下直接調用Invoke。有一個小的開銷與調用InvokeRequired然後直接去掉 - 關於Hans Passant對這個問題的評論。但是,只要代理正在執行重要的工作,或者此代碼不在熱點地區,代碼清晰度的開銷應該小於代碼清晰度。

更何況InvokeRequired可以給控制柄上的誤導結果尚未分配。該documentation狀態:

如果控件的句柄尚不存在,InvokeRequired向上搜索 控件的父鏈,直到它找到一個控制或形式,它 窗口句柄。如果找不到合適的句柄,則InvokeRequired方法返回false。

這意味着InvokeRequired可以返回false,如果調用不 要求(在同一線程上發生的通話),或者如果控制是在不同的線程,但在控件的句柄尚未 創建創建 。

在控件的句柄尚未創建的情況下, 不應該簡單地調用控件的屬性,方法或事件。 這可能會導致控件的句柄在背景 線程上創建,在沒有消息泵的情況下隔離線程上的控件,並使應用程序不穩定。

您可以通過檢查 的值來防止此情況,當InvokeRequired在背景 線程上返回false時IsHandleCreated。如果控制手柄尚未創建,則必須等待 ,直到它在調用Invoke或BeginInvoke之前創建。 通常情況下,只有在應用程序的主窗體的 構造函數中創建了後臺線程(如在 Application.Run(new MainForm())中,在窗體顯示之前創建了後臺線程或 Application.Run調用。

所以我會採取從上面的最後引用的段落的意見和替換以上的風險InvokeRequired代碼:

control.Invoke(action); 
+0

感謝大衛,我希望;-) – Hinek

0

您可以檢查是否需要調用Invoke

if (myForm.InvokeRequired) 
{ 
    // do invoke staff 
} else 
{ 
    // just execute your code without invoking 
} 
+2

雖然你可以檢查答案,這樣做有什麼意義呢? –

+0

要知道什麼時候叫代碼執行不同的線程,我需要'Invoke'與控制工作。我從你的帖子中看到這不是開銷。 – Samich

+0

看到我的答案。你可以直接調用'Invoke'並跳過'InvokeRequired'測試。但是我的問題是,使用你的代碼版本你會得到什麼? –

相關問題