首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Thread.Yield对WaitOne

Thread.Yield对WaitOne
EN

Stack Overflow用户
提问于 2018-10-26 15:09:10
回答 1查看 430关注 0票数 0

据我所知,可以使用Thread.Yield代替WaitOneManualResetEvent来进行线程信令。

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

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

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

P.S:以下是两个版本的示例代码,供演示之用:

代码语言:javascript
复制
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
代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

发布于 2018-10-26 23:04:36

首先,汉斯的评论是完全正确的:你正在发明你自己的旋转等待,糟糕。别干那事!

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

这是一个实现细节,我手头没有运行时的源代码;实际的实现是在一个名为WaitOneNative的本机函数中。不过,我可以给你一些想法。

首先,您正确地注意到,Thread.Yield是一个更原始的操作,因此它可以作为构建更高级别操作(如WaitOne )的策略的一部分。但实际上,它可能不会像你所描述的那样简单地使用,原因有几点:

  • Thread.Yield确实创建了一个屏障,但从代码中并不能百分之百地看出bool的读取没有被删除,或者写不能延迟。我们想要非常,非常肯定的是,bool写的东西被捡起来了,而引入障碍并没有破坏性能。
  • Thread.Yield将控制切换到当前处理器上的任何就绪线程。如果当前处理器上没有就绪线程,会发生什么情况?也许好好想想吧。是什么使这些代码不能加热整个CPU?如果要写入的线程位于不同的处理器上,会发生什么情况?涉及线程饥饿等的所有可能的场景是什么?
  • 考虑一下这个场景:我们有一个具有三个线程的超级线程处理器,Alpha、Bravo和Charlie,Alpha和Bravo目前正在CPU中执行。阿尔法还有1000万纳秒在它的量子,它看到标志是假的,并将其剩余的量子输出给查理。一纳秒后,Bravo设置了旗子。我们刚刚承担了一个上下文切换的全部成本,Alpha放弃了做一千万纳秒工作的机会!对于Alpha来说,更好的做法是旋转并燃烧其1000万纳秒中的几十个,而不是承担上下文切换的巨大代价。--这是在设计新的线程基元时必须考虑的几种场景。仅仅正确的控制流是不够的;你在热门的道路上做了一个糟糕的决定,你可以将性能降低数千或数百万倍。
  • 诸若此类。

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

好的。CLR有它必须维护的不变量。您必须记住,( CLR )从根本上说是作为COM的扩展而发明的,并且底层的实现深深地嵌入到COM世界中。特别是,所有关于编组的规则仍然适用。WaitOne有效地使线程处于休眠状态,但这可能会导致封送处理程序出现问题。克里斯·布鲁姆( Chris )关于这一点的文章特别令人恐惧和私奔:

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

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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53011616

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档