在线程中等待标志的最佳方法
Posted
技术标签:
【中文标题】在线程中等待标志的最佳方法【英文标题】:Best way to wait for flag in thread 【发布时间】:2019-07-30 22:31:35 【问题描述】:我有一个运行多个线程的 C++ 程序。我正在使用全局标志来告诉我什么时候可以继续我的程序。这需要使用等待设置标志的 while 循环。我知道这种方法不是最好的,因为程序运行的时间比预期的要长得多。
我已经看到了互斥体和条件变量的使用,但我不确定它是否适用于我的需求或如何实现。
volatile bool flag;
int threadFunction()
//Do some initialization work
//
//Then look for flag to be set
while (1)
if (flag)
//do stuff
flag = false;
Sleep(1);
int setFlag()
flag = true;
int main()
std::thread thread1(threadFunction);
while (1)
setFlag();
Sleep(5);
thread1.join()
threadFunction 中的 while 循环似乎导致了速度问题。有没有更好的方法来做到这一点?
没有错误,但代码似乎效率很低。
【问题讨论】:
与您的问题没有任何关系,但几乎总是if (flag) do_stuff(); flag = false;
是错误的。更好的是if (flag) flag = false; do_stuff();
【参考方案1】:
您目前拥有的是忙碌的等待,有时也称为自旋锁。这些可以在某些情况下提供良好的性能(主要是在等待时间很短且不频繁的情况下),但也可能导致 CPU 负载过度占用 CPU 内核,而这些 CPU 内核可能正在执行生产性工作。
另一个选项是阻塞标志。这将使用操作系统提供的工具在等待某些条件时阻止您的线程。这将防止它无所事事地占用 CPU 资源,因为操作系统知道只要您的线程正在等待,它就可以调度另一个线程。它还可能增加延迟,因为一旦您的线程等待的条件发生,操作系统必须重新安排您的线程。使用自旋锁,您的线程已经在执行,并且可以使用其剩余时间片立即进行生产性工作。
您可以从条件变量和互斥体构建一个简单的阻塞标志:
class Flag
public:
Flag() : flag_false
void set()
std::lock_guard g(mutex_);
flag_ = true;
cond_var_.notify_all();
void clear()
std::lock_guard g(mutex_);
flag_ = false;
void wait()
std::unique_lock lock(mutex_);
cond_var_.wait(lock, [this]() return flag_; );
private:
bool flag_;
std::mutex mutex_;
std::condition_variable cond_var_;
;
Live Demo
您需要哪种类型的锁定机制在很大程度上取决于您的特定工作负载。与所有性能问题一样,了解哪个最适合您的唯一方法是进行基准测试。
【讨论】:
flag
应该是std::atomic
,我想。
@PaulSanders 它不需要是原子的。它是谓词数据,因此 all 访问应该已经是互斥的,这要归功于该互斥锁。
@PaulSanders flag_
在这里不需要是原子的,因为互斥体提供了内存屏障。
@MilesBudnek 这没什么大不了的,但是将 notify_all
调用移到包含互斥锁的块内可以提高性能。然后,一个好的实现知道notify_all
调用不可能使线程准备好运行并且不能与任何东西抗衡,从而允许它在快速路径上执行。由于 OP 关心性能,因此最好的方式似乎是一个好主意。
@DavidSchwartz 有趣。我总是听到相反的建议:当你持有相关的互斥锁时,你应该避免通知等待条件变量的线程,因为线程会唤醒并立即再次阻塞。我将不得不做一些进一步的阅读。【参考方案2】:
目前您在代码中有“忙等待”和/或延迟问题。
使用std::condition_variable
和std::mutex
。
有关详细信息,请参阅 C++ 参考。它包含您需要的所有示例和说明。
【讨论】:
同样volatile bool flag;
应该是std::atomic <bool> flag;
以上是关于在线程中等待标志的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章
java 线程 wait join sleep yield notify notifyall synchronized