如何在使用Dispatcher.Run()时避免竞争条件?
本文关键字:竞争 条件 Run Dispatcher | 更新日期: 2023-09-27 17:54:06
我发现关于如何正确使用Dispatcher类的信息很少。
目前我正在使用类似于这个问题,但有一个固有的竞争条件,我没有看到任何地方提到。
假设您使用以下代码来启动调度程序线程:
Thread thread = new Thread(Dispatcher.Run);
thread.Start();
并尝试以后使用它:
Dispatcher.FromThread(thread).Invoke(MyMethodDelegate);
这通常会抛出NullReferenceException作为Dispatcher。FromThread调用可能返回null,因为不能保证Dispatcher。
为了正确地实现这一点,我所做的是在主线程上继续使用dispatcher之前使用一个信号来确保它正在运行。
这是一个较短的版本,作为一个实用程序函数,受你的启发,所以我省略了评论。
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;
}
}
这是我最终做的,我认为为了正确使用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