我正在使用VS 2012,.Net 4.5。
执行此代码(只需从有关线程的文章中升级一些示例):
using System.Threading;
class BasicWaitHandle
{
static EventWaitHandle wh = new AutoResetEvent(false);
static void Main()
{
new Thread(Waiter).Start();
new Thread(Waiter).Start();
Thread.Sleep(1000); // Подождать некоторое время...
wh.Set(); // OK – можно разбудить
wh.Set();
Console.ReadLine();
}
static void Waiter()
{
Console.WriteLine("Avait..."+Thread.CurrentThread.ManagedThreadId);
wh.WaitOne(); // Ожидать сигнала
Console.WriteLine("Got a signal"+Thread.CurrentThread.ManagedThreadId);
}
}
我调试了几次,但通常(并非总是)得到错误的结果。首先(一次或多次)它是正确的:
Avait...10
Avait...11
Got a signal 11
Got a signal 10
但是它刚开始跳过一个帖子(有些时候是第一个?有时是第二个):
Avait...10
Avait...11
Got a signal 11 (or 10)
程序只是没有反应。在几分钟内,它会给出一些正确的结果,但之后又会出错......
此外,当我一步一步地调试它时,它总是正确地运作。
那么,也许我应该选择另一种方法?但这看起来像我的预期,即使线程以随机顺序获得信号......
答案 0 :(得分:1)
我很不确定你可以对多个 awaters 使用相同的AutoResetEvent
,因为Set
不等待第一个线程完成其Wait
:
无法保证每次调用Set方法都会从EventWaitHandle释放一个线程,其复位模式为EventResetMode.AutoReset。如果两个调用太靠近,那么第二次调用在线程释放之前发生,则只释放一个线程。就好像第二次通话没有发生一样。此外,如果在没有线程等待并且已经发出EventWaitHandle信号时调用了Set,则该调用无效。
我会使用ManualResetEvent
并在设置信号期间同步(以确保等待线程接收信号)或(更好)使用每个等待功能的专用事件(每个线程都会从它自己的事件开始等待,你将需要那些线程来创建等待事件的管理器,并且Set
方法将发出所有这些事件的信号。)
p.s。:可以用俄语btw ^^
重复上述说法答案 1 :(得分:0)
两个线程都会启动并运行,直到它们阻塞WaitHandle。设置WaitHandle后,将唤醒一个线程并重置事件。
您无法保证哪个线程会被唤醒,因此无法确保订单。正确运行时,每次都会唤醒10或11,然后是另一个。
如果您的应用程序挂起,则问题是执行顺序。主线程在第一个线程唤醒之前执行对Event.Set()的两次调用。 AutoResetEvent不是计数器,它是设置或未设置,因此第二次调用Set()会丢失。
如果你在Set()之间调用Sleep(),你将屈服于其他线程并给其中一个时间唤醒并重置事件。
如果它正常工作,你只是运气好,等待线程有机会在调用Set()之间运行。这被称为竞争条件。