有时您会遇到这样的情况:一个线程需要等待,直到它从另一个线程获得信号为止。目前,我通过以下方式实现这一目标:
(存在另一个线程设置的volatile int signal;
来告诉等待的线程继续)
方法1:本能地等待时间最短,但CPU使用率最高:
while(signal != 1);
方法2:仍然使用100%cpu / core,但是我认为更好地为其他线程提供了运行的机会?延迟仍然很低
while(signal != 1) Sleep(0);
方法3:等待时导致的CPU使用率可以忽略不计(在任务管理器中报告为0%),但是显然有1ms的延迟。
while(signal != 1) Sleep(1);
是否有更好的方法来处理这种情况?主要对本机c ++ Win32感兴趣,但对linux / android / ios也感兴趣。
如果没有一种神奇的低延迟/低等待cpu使用率解决方案,那么我对以下两种情况下的最低延迟解决方案感兴趣:等待cpu使用率无关紧要,并且等待cpu使用率应忽略不计。 / p>
很抱歉,这是一个菜鸟问题,但是我对这种事情还是陌生的。
答案 0 :(得分:2)
这里的许多“正确”答案取决于您对延迟与吞吐量的重视程度,即,该特定线程在发出信号后尽快开始处理,还是其他线程获得响应,这是否更重要?等待期间的最大CPU时间?在很多情况下,所需的还取决于线程在准备好继续执行之前要等待多长时间。
现在,您要进行繁忙的等待-也就是说,在等待时,您在某种程度上保持CPU的(至少一个核心)繁忙,以检查它是否可以继续进行。< / p>
执行Sleep(0)
基本上会将当前线程放在准备执行并等待CPU执行的线程队列的 back 中。因此,如果没有其他线程在等待,它将仍然消耗100%的CPU。另一方面,如果具有相同优先级的其他线程准备好运行,它们将有机会在再次调度该线程之前运行。
尽管有一点:volatile
并不是真正为像这样的线程间通信定义的,所以您想改用原子变量。
std::atomic<bool> signal { false };
while (!signal)
Sleep(0); // or Sleep(1)
如果 您只希望它在signal
变成true
之前需要花费几毫秒(或类似的时间),这样线程可以继续进行就可以了。由于等待时间不长,因此等待时它不会占用大量CPU时间,并且(特别是如果系统负载较轻时)可以在signal
变为true
时非常快速地响应。 / p>
如果线程可能等待的时间超过几毫秒,则最好采用某种机制,该机制采用当前线程并将其标记为未准备好运行,而是在等待某个内核对象之后才可以运行/将再次安排。 Windows为此提供了Event
:
HANDLE signal = CreateEvent(/* ... */);
WaitForSingleObject(signal, INFINITE);
当其他代码想要表明该线程应该运行时,它会执行以下操作:
SetEvent(signal);
在这种简单情况下,Windows事件可能会很好地起作用-但是在复杂情况下,获得所需的信息可以在困难和完全不可能之间运行参差不齐的边缘(尽管大多数情况下,变得困难的确是因为您可能应该使用除了事件以外的其他内容。
您也可以使用标准库中的条件变量,但这有点复杂。条件变量始终与互斥量以及您关注的条件一起使用。因此,将其用于您的案例看起来像这样:
std::atomic<bool> signal;
std::mutex m;
std::condition_variable v;
std::unique_lock<std::mutex> lock(m);
v.wait(lock, [&] { return signal; });
...而对于其他表示该线程可以执行的代码,它将执行以下操作:
std::unique_lock<std::mutex> lock(m);
signal = true;
v.notify_one();
条件变量确实具有优势,但是无论如何它都不是最简单的使用。另一方面,一旦您习惯了所涉及的样板,也不是特别困难。