EventWaitHandle有时候!跳过线程

时间:2014-01-13 14:58:20

标签: c# multithreading event-wait-handle

我正在使用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)

程序只是没有反应。在几分钟内,它会给出一些正确的结果,但之后又会出错......

此外,当我一步一步地调试它时,它总是正确地运作。

那么,也许我应该选择另一种方法?但这看起来像我的预期,即使线程以随机顺序获得信号......

2 个答案:

答案 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()之间运行。这被称为竞争条件。