繁体   English   中英

Thread.Yield与WaitOne

[英]Thread.Yield vs. WaitOne

据我了解, Thread.Yield发出线程信号的目的,可以使用Thread.Yield代替WaitOneManualResetEvent

尽管我还没有看到一个文档来解释WaitOne在幕后的确切行为,但我认为它将线程置于Wait状态,并告诉OS调度程序每次在该线程轮到时检查是否设置了ManualResetEvent 。队列。 如果未设置,则调度程序不执行上下文切换,而是跳到另一个线程。 如果设置,则调度程序将线程置于运行状态,以便WaitOne之后的代码开始执行。

另一方面,无论ManualResetEvent的状态如何,使用Thread.Yield都将导致上下文切换,然后进行检查。

我的理解正确吗? 是否有文档解释WaitOne的内部工作原理?

PS:这是用于演示目的的两个版本的示例代码:

var signal = new ManualResetEvent(false);
new Thread(() =>
{
    Console.WriteLine("Waiting for signal...");
    signal.WaitOne();
    signal.Dispose();
    Console.WriteLine("Got signal!");
}).Start();
Thread.Sleep(2000);
signal.Set(); // "Open" the signal

bool signal = false;
new Thread(() =>
{
    Debug.WriteLine("Waiting for signal...");
    while(signal == false)
    {
        Thread.Yield();
    }
    Debug.WriteLine("Got signal!");
}).Start();
Thread.Sleep(2000);
signal = true; ; // "Open" the signal

首先,汉斯的评论是完全正确的:您正在发明自己的旋转等待,非常糟糕。 不要那样做!

就是说,您的问题不是关于是否应该重新实现WaitOne,而是因为没有编写WaitOne的人是如何实现WaitOne的。 考虑这个问题是完全合理的; 这些功能不是神奇的,而是由人类实现的,那么它们是如何做到的呢?

这是一个实现细节,我没有方便的运行时源代码。 实际的实现是在名为WaitOneNative的本机函数中WaitOneNative 但是,我可以给您一些想法。

首先,您正确地注意到Thread.Yield是更原始的操作,因此可以将其用作构建诸如WaitOne类的更高级别操作的策略的一部分。 但是实际上,由于以下几个原因,可能不会以您描述的幼稚方式使用它:

  • Thread.Yield确实会创建一个障碍,但是从代码中并不是100%显而易见的是没有消除对bool的读取,或者不能延迟写入。 我们要非常非常确定地确定布尔写操作,并且引入障碍不会破坏性能。

  • Thread.Yield将控制权Thread.Yield当前处理器上的任何就绪线程。 如果当前处理器上没有就绪线程,该怎么办? 也许考虑一下。 是什么使该代码无法加热整个CPU? 如果要执行写操作的线程在不同的处理器上会发生什么? 涉及线程匮乏等所有可能的方案是什么?

  • 考虑这种情况:我们有一个具有三个线程的超线程处理器,Alpha,Bravo和Charlie,并且Alpha和Bravo当前正在CPU中执行。 Alpha的量子剩余时间为1000万纳秒,它发现该标志是错误的,并将其剩余的量子提供给Charlie。 一纳秒后,Bravo设置了标志。 我们只承担了上下文切换的全部费用,而Alpha放弃了进行一千万纳秒工作的机会! 对于Alpha来说,旋转等待并消耗其一千万纳秒中的几十个,而不是花费上下文切换的巨额成本会更好。 在设计新的线程原语时,必须考虑这些情况 仅使控制流程正确还不够。 您在热路径上做出错误的决定,可能会使性能降低数千或数百万。

  • 等等。

但是,等等,情况变得更糟。 WaitOne是否需要解决更多细微的问题?

当然。 CLR具有必须维护的不变式。 您必须记住, CLR是从根本上发明的,是对COM的扩展 ,其底层实现已深深地嵌入到COM世界中。 特别是,关于编组的所有规则仍然适用。 WaitOne有效地使线程进入睡眠状态,但是这可能导致编组器出现问题。 克里斯·布鲁姆(Chris Brumme)在这方面的文章特别令人恐惧和困扰:

https://blogs.msdn.microsoft.com/cbrumme/2004/02/02/apartments-and-pumping-in-the-clr/

阅读它,看看您是否能理解所有内容。 自2004年以来,我已经阅读了数十次,而且我曾经是一名专业的COM程序员,我大概得到了其中的80%。 这是一件很复杂的事情,如果您不了解,您将无法编写满足CLR需求的WaitOne正确实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM