【问题标题】:Why does the second thread get released before the first one, when they both called WaitOne() and were released by an AutoResetEvent?为什么第二个线程在第一个线程之前被释放,当它们都调用 WaitOne() 并被 AutoResetEvent 释放时?
【发布时间】:2009-04-10 00:09:45
【问题描述】:

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

我进行了一项测试,以了解当您设置多个线程正在等待的 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();
    }

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

【问题讨论】:

  • 尝试调用autoEvent1.Set();再次查看其他线程是否会被释放。我想你需要把开关转两下。
  • 嗨 - 是的,我马上就尝试过了 - 我可以让第二个线程继续第二次调用 Set() - 但前提是我引入了延迟,例如调用 Thread.Sleep()。
  • 我目前更感兴趣的是看看是否有人真的知道被释放的线程是随机的。文档说线程排队表明某种排序(这就是为什么我希望第一个线程首先释放)。
  • 来自这里:msdn.microsoft.com/en-us/library/… 不能保证每次调用 Set 方法都会释放一个线程。如果两个调用靠得太近,以至于第二个调用发生在一个线程被释放之前,那么只有一个线程被释放。
  • 文档在哪里 :-)

标签: c# .net multithreading resetevent


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    来自 MSDN

    ManualResetEvent 上的 MSDN:“线程 调用 WaitOne ManualResetEvent 将阻塞,等待 信号。当控制 线程完成活动,它 呼叫设置以发出等待的信号 线程可以继续。 所有等待线程都被释放。

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

    "

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 好的-感谢您的确认-知道为什么第二个线程首先被释放吗?这似乎总是如此,还是总是最后一个调用 WaitOne() 的线程将被释放(而其他线程必须等待另一个对 Set() 的调用?
      • 我猜这不是你会如何使用它顺便说一句:)。不过我还是很好奇。
      • 似乎合乎逻辑,因为您最后阻止它,它将覆盖 t1 的等待并被集合唤醒。 IE。最后一个阻止获胜。不是 100% 确定这一点,对于线程,最好假设它是随机的。 :)
      猜你喜欢
      • 2016-03-21
      • 2015-11-07
      • 2011-05-20
      • 1970-01-01
      • 1970-01-01
      • 2011-12-15
      • 2013-03-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多