EventWaitHandle sometimes! skip thread

2.1k views Asked by At

I am using VS 2012, .Net 4.5.

Execute this code (just upgrade some sample from article about threading):

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);
}
}

I Debug it few times, but usually (not always) get wrong result. At first (once or more times) it correct:

Avait...10
Avait...11
Got a signal 11
Got a signal 10

But then it just start skipping one thread (somethimes first? somethimes second):

Avait...10
Avait...11
Got a signal 11 (or 10)

And program just does not react. In a few minutes it gives some correct results, but then go wrong again...

Moreover, when i debugging it step-by-step it always acting correctly.

So, maybe I should choose another approach? But this looks like what I expected, even if threads got signals in random order...

2

There are 2 answers

1
Sinatr On BEST ANSWER

I am pretty unsure you can use same AutoResetEvent for multiple awaters, because Set is not waiting for first thread to complete its Wait:

There is no guarantee that every call to the Set method will release a thread from an EventWaitHandle whose reset mode is EventResetMode.AutoReset. If two calls are too close together, so that the second call occurs before a thread has been released, only one thread is released. It is as if the second call did not happen. Also, if Set is called when there are no threads waiting and the EventWaitHandle is already signaled, the call has no effect.

I'd go with ManualResetEvent and synchronization during setting signal (to ensure, what waiting thread receive signal) or (better) use dedicated event for each waiting function (every thread would start with its own event to wait for, you will need kind of manager for those thread to create waiting event and to have Set method what will signal all these events).

p.s.: can repeat said above in russian btw ^^

0
Mike Haboustak On

Both threads start and run until they block on the WaitHandle. When the WaitHandle is set, one thread will wake up and the event will reset.

You can't guarantee which thread will wake up, so the order isn't ensured. When running correctly, either 10 or 11 will wake up, followed by the other, every time.

In the case where your application hangs, the problem is the execution order. The main thread is executing both calls to Event.Set() prior to the first thread waking up. The AutoResetEvent is not a counter, it is either set or unset, so the second call to Set() is lost.

If you Sleep() between calls to Set(), you will yield to the other threads and give one of them time to wake up and reset the event.

In the case where it works correctly, you are just getting lucky and the waiting threads are getting a chance to run between calls to Set(). This is referred to as a race condition.