使用Dispatcher.Run()时如何避免竞争条件?

时间:2011-05-02 16:16:13

标签: c# dispatcher

我发现很少有关于如何正确使用Dispatcher类的信息。

目前我使用它与this question类似,但有一种固有的竞争条件,我在任何地方都没有提到。

假设您使用以下代码启动调度程序线程:

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

稍后尝试使用它:

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

这通常会抛出NullReferenceException,因为Dispatcher.FromThread调用可能会返回null,因为无法保证已调用Dispatcher.Run。

我为正确实现这一点所做的是在继续在主线程上使用它之前使用信号来确保调度程序正在运行。

2 个答案:

答案 0 :(得分:4)

这是一个较短的版本,作为实用功能完成,受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;
    }
}   

答案 1 :(得分: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

Dispatcher.FromThread(executionThread).BeginInvoke

编组调度程序线程的调用。