WinForm 程式中,背景工作執行緒嘗試更新主視窗控制項時,文件警告不支援多執行緒呼叫,實際執行常導致當機。原因在於所有繼承自 Control 的類別(含 Control 本身)仰賴 Windows 訊息迴圈,訊息只會送達建立視窗的執行緒。即使有同步機制,也無法從其他執行緒呼叫處理訊息的方法。WinForm 以委派將訊息繫結至事件處理器,但只有建立表單的執行緒能正確處理事件。非訊息處理的方法則可從任何執行緒呼叫。
Control 實作 System.ComponentModel.ISynchronizeInvoke,提供跨執行緒呼叫的標準機制:
public interface ISynchronizeInvoke
{
object Invoke(Delegate method, object[] args);
IAsyncResult BeginInvoke(Delegate method, object[] args);
object EndInvoke(IAsyncResult result);
bool InvokeRequired { get; }
}
Invoke() 會阻塞呼叫執行緒,將呼叫封送至目標執行緒執行,再將結果送回。以委派定位方法,參數為物件陣列。
呼叫端可先檢查 InvokeRequired。若為 false(同一執行緒),可直接呼叫方法;若為 true,則透過 Invoke() 封送。
Form form;
// 取得表單參考
ISynchronizeInvoke synchronizer = form;
if (synchronizer.InvokeRequired)
{
MethodInvoker invoker = new MethodInvoker(form.Close);
synchronizer.Invoke(invoker, null);
}
else
{
form.Close();
}
此模式確保 UI 操作永遠在 UI 執行緒執行,避免競爭條件與存取違規。