2011-05-02 122 views
4

我發現關於如何正確使用Dispatcher類的信息很少。如何在使用Dispatcher.Run()時避免競爭條件?

目前我使用它類似this question,但有一個固有的競爭條件,我沒有看到任何地方提到。

假設你使用下面的代碼來啓動一個調度程序線程:

Thread thread = new Thread(Dispatcher.Run); 
thread.Start(); 

而稍後再嘗試使用它:

Dispatcher.FromThread(thread).Invoke(MyMethodDelegate); 

這往往會拋出一個NullReferenceException作爲Dispatcher.FromThread,通話可能由於不能保證Dispatcher.Run已被調用,因此返回null。

我已經做了適當的實現是使用信號來確保調度程序在繼續在主線程中使用之前運行。

+1

比賽條件沒有任何其他線程開始競爭條件不同,它聽起來像你已經解決了你的問題。你有什麼問題? – 2011-05-02 17:06:14

+0

是的 - 比賽條件沒有任何其他比賽條件不同。我擔心的是,它是固有的(我相信)你應該使用Dispatcher API,但是在MSDN的任何地方都沒有評論它如何正確使用它。 – Travis 2011-05-03 02:52:44

+0

這不是Dispatcher的典型用法。通常,您的主線程上有一個Dispatcher(爲您自動創建),就是這樣。擁有多個UI線程的每個線程都有自己的Dispatcher是非常不尋常的。將調度程序用於非UI線程更是不尋常,這正是您在這裏所做的。如果你遠離這條蜿蜒曲折的道路,期望不得不破解叢林。 – 2011-05-03 12:23:40

回答

2

這是我最終做的,這是我相信你需要做的,以便正確使用Dispatcher。

private Thread executionThread; 
private object SyncObject {get;set;} 
private delegate void DispatcherMethod(); 

private void InitDispatcher() 
{ 
    this.SyncObject = new object(); 

    // Set up the dispatcher pump. See Dispatcher.Run on MSDN. 
    this.executionThread = new Thread(StartDispatcher); 

    lock (this.SyncObject) 
    { 
     this.executionThread.Start(); 
     Monitor.Wait(this.SyncObject); 
    } 
} 


private void StartDispatcher() 
{ 
    DispatcherMethod method = DispatcherStarted; 
    // Enqueue a started event by adding an initial method on the message pump. 
    // Use BeginInvoke because the dispatcher is not actually running yet. 
    // The call to Dispatcher.CurrentDispatcher handles creating the actual 
    // Dispatcher instance for the thread (see MSDN - Dispatcher.FromThread 
    // does not initialize the Dispatcher). 
    Dispatcher.CurrentDispatcher.BeginInvoke(method); 
    Dispatcher.Run(); 
} 


private void DispatcherStarted() 
{ 
    lock (this.SyncObject) 
    { 
     Monitor.Pulse(this.SyncObject); 
    } 
} 

InitDispatcher返回後,您可以使用

Dispatcher.FromThread(executionThread).Invoke 

​​

元帥到調度線程調用。

3

這是一個較短的版本,作爲效用函數完成,靈感來自yours,所以我忽略了評論。

private static Thread CreateDispatcherThread() 
{ 
    using (var startedEvent = new ManualResetEventSlim()) 
    { 
     var dispatcherThread = new Thread(_ => { 
      Dispatcher.CurrentDispatcher.BeginInvoke((Action)(startedEvent.Set)); 
      Dispatcher.Run(); }); 
     dispatcherThread.Start(); 
     startedEvent.WaitHandle.WaitOne(); 
     return dispatcherThread; 
    } 
}