为什么第二个线程在第一个线程之前被释放,当它们都调用WaitOne()并由AutoResetEvent释放时?

时间:2021-05-18 09:43:40

Suppose that ThreadA and ThreadB both call WaitOne() in that order on the same AutoResetEvent. When the event is set, why does ThreadB get released instead of ThreadA?

假设ThreadA和ThreadB都在同一个AutoResetEvent上按顺序调用WaitOne()。设置事件后,为什么ThreadB会被释放而不是ThreadA?

I ran a test to find out what happens when you set an AutoResetEvent on which mutiple threads are waiting:

我运行了一个测试,以了解当您设置多个线程正在等待的AutoResetEvent时会发生什么:

    private static void Test()
    {
        // two threads - waiting for the same autoreset event
        // start it unset i.e. closed i.e. anything calling WaitOne() will block
        AutoResetEvent autoEvent = new AutoResetEvent(false);

        Thread thread1 = new Thread(new ThreadStart(WriteSomeMessageToTheConsole));
        thread1.Start();  // this will now block until we set the event

        Thread thread2 = new Thread(new ThreadStart(WriteSomeOtherMessageToTheConsole));
        thread2.Start();  // this will now also block until we set the event

        // simulate some other stuff
        Console.WriteLine("Doing stuff...");
        Thread.Sleep(5000);
        Console.WriteLine("Stuff done.");

        // set the event - I thought this would mean both waiting threads are allowed to continue
        // BUT thread2 runs and thread1 stays blocked indefinitely
        // So I guess I was wrong and that Set only releases one thread in WaitOne()?
        // And why thread2 first?
        autoEvent1.Set();
    }

The code is of course not useful; it's just a mickey mouse example. And this is not important/urgent. But I'd be interested to know more anyway...

代码当然没用;这只是一个米老鼠的例子。这不重要/紧急。但我还是有兴趣知道更多......

3 个解决方案

#1


IIRC, which thread is released by an auto-reset event is unspecified. As everyone else mentioned, you want a manual reset event if you want to broadcast a condition. If you want to release an exact number (say exactly 3 of n), then you probably want to use a semaphore.

IIRC,由自动重置事件释放的线程未指定。正如其他人提到的那样,如果要广播条件,则需要手动重置事件。如果你想发布一个确切的数字(比如说n中的3个),那么你可能想要使用一个信号量。

If you really want to dig into why the order might be different than you would expect, take a look at "Windows Internals" or anything that Mark Russinovich has written. Chances are that he explains the wait order on executive resources somewhere.

如果您真的想深入了解为什么订单可能与您预期的不同,请查看“Windows Internals”或Mark Russinovich撰写的任何内容。有可能他在某处解释了执行资源的等待顺序。

#2


From MSDN

MSDN on ManualResetEvent: "Threads that call WaitOne on the ManualResetEvent will block, awaiting the signal. When the controlling thread completes the activity, it calls Set to signal that the waiting threads can proceed. All waiting threads are released.

ManualResetEvent上的MSDN:“在ManualResetEvent上调用WaitOne的线程将阻塞,等待信号。当控制线程完成活动时,它调用Set来表示等待线程可以继续。所有等待线程都被释放。

But for AutoResetEvent, MSDN says: "Calling Set signals AutoResetEvent to release a waiting thread. AutoResetEvent remains signaled until a single waiting thread is released, and then automatically returns to the nonsignaled state. If no threads are waiting, the state remains signaled indefinitely.

但对于AutoResetEvent,MSDN说:“调用Set信号AutoResetEvent释放一个等待的线程.AutoResetEvent保持信号状态,直到释放一个等待线程,然后自动返回到无信号状态。如果没有线程在等待,状态将无限期地发出信号。

"

#3


On an AutoResetEvent, Set only releases one thread. You should use a ManualResetEvent to release multiple waiting threads.

在AutoResetEvent上,Set仅释放一个线程。您应该使用ManualResetEvent释放多个等待线程。

#1


IIRC, which thread is released by an auto-reset event is unspecified. As everyone else mentioned, you want a manual reset event if you want to broadcast a condition. If you want to release an exact number (say exactly 3 of n), then you probably want to use a semaphore.

IIRC,由自动重置事件释放的线程未指定。正如其他人提到的那样,如果要广播条件,则需要手动重置事件。如果你想发布一个确切的数字(比如说n中的3个),那么你可能想要使用一个信号量。

If you really want to dig into why the order might be different than you would expect, take a look at "Windows Internals" or anything that Mark Russinovich has written. Chances are that he explains the wait order on executive resources somewhere.

如果您真的想深入了解为什么订单可能与您预期的不同,请查看“Windows Internals”或Mark Russinovich撰写的任何内容。有可能他在某处解释了执行资源的等待顺序。

#2


From MSDN

MSDN on ManualResetEvent: "Threads that call WaitOne on the ManualResetEvent will block, awaiting the signal. When the controlling thread completes the activity, it calls Set to signal that the waiting threads can proceed. All waiting threads are released.

ManualResetEvent上的MSDN:“在ManualResetEvent上调用WaitOne的线程将阻塞,等待信号。当控制线程完成活动时,它调用Set来表示等待线程可以继续。所有等待线程都被释放。

But for AutoResetEvent, MSDN says: "Calling Set signals AutoResetEvent to release a waiting thread. AutoResetEvent remains signaled until a single waiting thread is released, and then automatically returns to the nonsignaled state. If no threads are waiting, the state remains signaled indefinitely.

但对于AutoResetEvent,MSDN说:“调用Set信号AutoResetEvent释放一个等待的线程.AutoResetEvent保持信号状态,直到释放一个等待线程,然后自动返回到无信号状态。如果没有线程在等待,状态将无限期地发出信号。

"

#3


On an AutoResetEvent, Set only releases one thread. You should use a ManualResetEvent to release multiple waiting threads.

在AutoResetEvent上,Set仅释放一个线程。您应该使用ManualResetEvent释放多个等待线程。