C++ 等待线程的最佳方式是什么?
有时,您会遇到这样的情况:一个线程需要等待,直到它从另一个线程获得信号。目前,我通过以下方式实现这一目标: 存在易失性int信号;由另一个线程设置,以通知等待的线程继续 方法1:本能地,等待时的延迟最低,但cpu使用率最高:C++ 等待线程的最佳方式是什么?,c++,multithreading,winapi,C++,Multithreading,Winapi,有时,您会遇到这样的情况:一个线程需要等待,直到它从另一个线程获得信号。目前,我通过以下方式实现这一目标: 存在易失性int信号;由另一个线程设置,以通知等待的线程继续 方法1:本能地,等待时的延迟最低,但cpu使用率最高: while(signal != 1); 方法2:仍然使用100%的cpu/内核,但我认为最好是给其他线程一个运行的机会?仍然非常低的延迟 while(signal != 1) Sleep(0); 方法3:在任务管理器中以0%的速度等待报告时,cpu使用率可以忽略不计,但
while(signal != 1);
方法2:仍然使用100%的cpu/内核,但我认为最好是给其他线程一个运行的机会?仍然非常低的延迟
while(signal != 1) Sleep(0);
方法3:在任务管理器中以0%的速度等待报告时,cpu使用率可以忽略不计,但显然有1ms的延迟
while(signal != 1) Sleep(1);
有没有更好的办法来处理这个案子?主要对本机C++ Win32感兴趣,同时对Linux/Android/iOS。
如果没有神奇的低延迟/低等待cpu使用率解决方案,我对以下两种情况下的最低延迟解决方案感兴趣:等待cpu使用率无关紧要,等待cpu使用率应该可以忽略不计
如果这是一个noob问题,我深表歉意,但我对这类事情还不熟悉。这里的许多正确答案取决于您对延迟和吞吐量的重视程度,也就是说,这个特定线程在发出信号后尽快开始处理是否更重要,或者其他线程在等待时获得最大的CPU时间?在很多情况下,需要什么还取决于线程等待多长时间才能准备好继续 现在,你正在做一个忙碌的等待,也就是说,当你等待的时候,你至少让CPU的一个核心处于某种程度的忙碌状态,检查它是否可以继续 执行Sleep0基本上将当前线程放在准备执行并等待CPU执行的线程队列的后面。因此,如果没有其他线程在等待,它仍然会消耗100%的CPU。另一方面,如果具有相同优先级的其他线程已准备好运行,则它们将有机会在再次调度此线程之前运行 不过有一点:volatile并不是像这样为线程间通信定义的,所以您希望使用原子变量
std::atomic<bool> signal { false };
while (!signal)
Sleep(0); // or Sleep(1)
当其他代码想要发出该线程应该运行的信号时,它会执行如下操作:
SetEvent(signal);
std::unique_lock<std::mutex> lock(m);
signal = true;
v.notify_one();
对于这种简单的情况,Windows事件可能工作得很好,但在复杂的情况下,获取所需的内容可能会在困难和完全不可能之间徘徊,尽管大多数情况下变得困难实际上是因为您可能应该使用事件以外的内容
您也可以使用标准库中的条件变量,但它有点复杂。条件变量始终与互斥体以及您关心的条件一起使用。因此,在您的案例中使用它看起来有点像这样:
std::atomic<bool> signal;
std::mutex m;
std::condition_variable v;
std::unique_lock<std::mutex> lock(m);
v.wait(lock, [&] { return signal; });
…对于另一个代码,它将执行如下操作来表示此线程可以运行:
SetEvent(signal);
std::unique_lock<std::mutex> lock(m);
signal = true;
v.notify_one();
条件变量确实有其优点,但无论如何,它都不是最简单的使用方法。另一方面,一旦您习惯了所涉及的样板文件,这也不是特别困难。这里的许多正确答案取决于您对延迟和吞吐量的重视程度,也就是说,这个特定线程在发出信号后尽快开始处理是否更重要,或者其他线程在等待时获得最大的CPU时间?在很多情况下,需要什么还取决于线程等待多长时间才能准备好继续 现在,你正在做一个忙碌的等待,也就是说,当你等待的时候,你至少让CPU的一个核心处于某种程度的忙碌状态,检查它是否可以继续 执行Sleep0基本上将当前线程放在准备执行并等待CPU执行的线程队列的后面。因此,如果没有其他线程在等待,它仍然会消耗100%的CPU。另一方面,如果具有相同优先级的其他线程已准备好运行,则它们将有机会在再次调度此线程之前运行 不过有一点:volatile并不是像这样为线程间通信定义的,所以您希望使用原子变量
std::atomic<bool> signal { false };
while (!signal)
Sleep(0); // or Sleep(1)
当其他代码想要发出该线程应该运行的信号时,它会执行如下操作:
SetEvent(signal);
std::unique_lock<std::mutex> lock(m);
signal = true;
v.notify_one();
对于这种简单的情况,Windows事件可能工作得很好,但在复杂的情况下,获取所需的内容可能会在困难和完全不可能之间徘徊,尽管大多数情况下变得困难实际上是因为您可能应该使用事件以外的内容
您也可以使用标准库中的条件变量,但它有点复杂。条件变量始终与互斥体以及您关心的条件一起使用。因此,在您的案例中使用它看起来有点像这样:
std::atomic<bool> signal;
std::mutex m;
std::condition_variable v;
std::unique_lock<std::mutex> lock(m);
v.wait(lock, [&] { return signal; });
…对于另一个代码,它将执行如下操作来表示此线程可以运行:
SetEvent(signal);
std::unique_lock<std::mutex> lock(m);
signal = true;
v.notify_one();
变异性条件
ble确实有优点,但无论如何,它都不是最简单的使用方法。另一方面,一旦您习惯了所涉及的样板文件,这也不是特别困难。使用std::condition\u变量请参见:。而且…这使得易失性对象适合与信号处理程序通信,但不适合与另一个执行线程通信,。。。源:与大多数现代OSES一样,Win32 API提供了几种类型的同步对象,C++也提供了上面注释中提到的,并且如@ RichardCritten所指出的,在您的用例中,波动性并不十分合适。那么为什么要做轮询循环呢?winapi有很多种方式。例如Event-一个线程等待事件另一个调用SetEvent。存在和其他解决方案。如果没有更多的上下文,则不可能说什么更好使用std::condition_变量请参见:。而且…这使得易失性对象适合与信号处理程序通信,但不适合与另一个执行线程通信,。。。源:与大多数现代OSES一样,Win32 API提供了几种类型的同步对象,C++也提供了上面注释中提到的,并且如@ RichardCritten所指出的,在您的用例中,波动性并不十分合适。那么为什么要做轮询循环呢?winapi有很多种方式。例如Event-一个线程等待事件另一个调用SetEvent。存在和其他解决方案。没有更多的上下文,就不可能说什么更好