我看到人们在我使用的大量多线程,多进程应用程序系统的某些部分执行此操作。它似乎围绕调试行完成:
std::cerr << "DEBUG: Reaching: " << __FUNCTION__ << " @ " << __LINE__ << std::endl;
sleep(0);
如果我将睡眠(0)微距化; (即将其更改为“”),系统的调试输出似乎有不同的顺序(不太可预测),所以我认为它使得线路更快出来 - 但我认为std :: cerr是无缓冲的,并且std: :无论如何,endl调用std :: flush(),为什么会这样呢?
答案 0 :(得分:12)
基本上,它会将控制权交还给调度程序,并让您立即重新安排。也就是说,尝试欺骗操作系统做某事基本上是一种破解。
愚弄操作系统永远不是一个好主意。
如果系统适当地欠载,那么进入休眠状态意味着操作系统获得控制并让I / O队列刷新,因此它会产生这种效果。有时。根据
它究竟在做什么取决于实施的细节,坦白地说,你不能依赖它。
答案 1 :(得分:8)
它以难以预测的方式扰乱了调度程序。
通常,结果类似于对pthread_yield()
的调用 - 您放弃了您的时间片。这样做的结果是,在大量的调试打印负载下,在写入cerr的过程中(即在<<
之间),你将不太可能被抢占,因为你将在一开始在最后一次调试打印之后的时间片,因此你不太可能让多个线程覆盖彼此的输出(即获得类似DEBUG: REACHING: foo() @ DEBUG: REACHING bar()17 @ 24
的东西)。
也就是说,这种方法不可靠 - 它扰乱了调度程序,而不是要求特定的语义。它也很慢 - 无条件地进入内核以产生(并且可能过于频繁地在多个线程之间弹跳控制)。并且它不太可能在多核CPU上正常工作。
最好将互斥量放在所有调试输出上,如下所示。也就是说,由于这是调试代码,因此作者可能已经使用快速而肮脏的黑客来使足够好来调试他们遇到的任何问题并不奇怪。
答案 2 :(得分:1)
在大多数平台上,sleep(0)
会使调度程序或多或少地处理当前线程,就好像它已经用完了它的时间片一样。通常,这意味着,如果可能的话,如果可以运行,则将在该核上安排同一进程中的另一个线程。正如您所指出的,它倾向于使调度更具可预测性。对我来说,这在调试时似乎适得其反。
我同意Nemo的评论,它与pthread_yield
大致相同。它确实有一些合法用途,但它有时被错误地用作提供更公平或减少延迟的方法。通常情况下,它会使性能变差,因为上下文切换会破坏缓存。
我看了其他的答案,我同意一般的痴迷感。我敢打赌除了有人认为更可预测的调度是一件好事之外,没有充分的理由。 (事实并非如此。灵活性很好。您对调度程序的要求越多,为满足这些要求而牺牲的就越多。如果您实施的要求实际上并不需要,那么您根本就无需交易性能。)
答案 3 :(得分:0)
您可以使用此方法让其他进程运行,这可能正在等待某些CPU时间,但如果没有其他进程等待运行,则不会强制执行特定的延迟。
答案 4 :(得分:0)
正如其他人所说,sleep(0)
是一个系统调用,导致当前线程放弃对CPU的控制。
我能想到的唯一正当理由是使用汇编指令(如LOCK(x86)和)实现自己的同步原语,例如自旋锁。 LDREX和STREX(ARMv7)。在这种情况下,如果我们遇到锁定,我们也可以立即放弃控制,希望另一个线程能够完成它并锁定我们的锁定。这肯定会消失,直到我们的时间片结束。
话虽如此,在实现自己的同步原语时,您确实需要知道自己在做什么。具体来说,您可能需要放入内存屏障来强制执行读写顺序。使用平台上提供的原语可能要好得多。