[英]Scheduling with EventWaitHandle with Dispatcher.BeginInvoke
下面的代码具有两个线程,每个线程将20的string str
写入其相应的文本框。 完成后, Thread t00
发出信号, Thread t00
Thread t01
启动并将共享string str
从y更改为x 。 Thread t00
应将20 y写入文本框, Thread t01
应将20 x写入另一个文本框。 相反, Thread t00
最终写入19 y和1 x 。 但是,如果在设置Thread.Sleep()
之前添加Thread.Sleep()
,可以解决我遇到的问题(我得到20 x和20 y ),但是为什么呢? EventWaitHandle
循环结束后,才不应该设置,有或无Thread.Sleep()
public partial class MainWindow : Window
{
public string str = "y";
static EventWaitHandle _waitHandle = new AutoResetEvent(false);
public MainWindow()
{
InitializeComponent();
Thread t00 = new Thread(() =>
{
for (int i = 0; i < 20; i++)
{
Thread.Sleep(200);
Action action00 = () =>
{
tb00.AppendText(str);
};
Dispatcher.BeginInvoke(action00);
}
Thread.Sleep(200); // <-- why this fix the problem??
_waitHandle.Set();
});
t00.Start();
Thread t01 = new Thread(() =>
{
Action action00 = () =>
{
tb01.AppendText("Waiting...\n");
};
Dispatcher.BeginInvoke(action00);
_waitHandle.WaitOne();
str = "x";
for (int i = 0; i < 20; i++)
{
Thread.Sleep(200);
Action action = () =>
{
tb01.AppendText(str);
};
Dispatcher.BeginInvoke(action);
}
});
t01.Start();
}
}
因为您正在使用BeginInvoke
。 BeginInvoke
异步调用UI线程上的委托。 它将消息放入UI线程消息队列中并返回,因此它返回的事实并不意味着实际执行了操作。
因此,在大多数情况下,当您设置等待句柄并且另一个线程接收到tb00.AppendText(str);
信号并将str
从y
更改为x
-仍然存在未调用的tb00.AppendText(str);
UI线程队列中的委托。 最终调用它时str
已经是x
。
Thread.Sleep
对此进行了“修复”,因为它为挂起的委托留出了一些时间在UI线程上执行。 使用Invoke
代替BeginInvoke
还可以“修复”该问题,因为Invoke
是同步的,并且仅在UI线程上实际执行了委托之后才返回。
想想BeginInvoke()
将工作单元推入队列。 当从工作队列中弹出第20个action00
并执行时, str='x'
已经执行,因此当action00
实际运行时,它将打印x
。
Thread.Sleep(200)
在执行str='x'
之前给第20个action00
时间弹出并运行,因此它将打印y
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.