使用易失性布尔变量忙于等待
Using volatile boolean variable for busy waiting
在阅读了其他开发人员编写的一些代码后出现了这个问题,所以我做了一些研究,我找到了Andrei Alexandrescu的文章。在他的文章中,他说可以使用易失性布尔变量来忙于等待(参见Wait/Wakeup的第一个示例)
class Gadget
{
public:
void Wait()
{
while (!flag_)
{
Sleep(1000); // sleeps for 1000 milliseconds
}
}
void Wakeup()
{
flag_ = true;
}
...
private:
bool flag_;
};
我真的不明白它是如何工作的。
- 易失性不保证操作是原子的。实际上对布尔变量的读取/写入是原子的,但理论并不能保证这一点。从我的角度来看,上面的代码可以通过使用 std::atomic::load/store 函数以及相应的获取/释放内存排序约束,使用 C++11 安全地重写。
- 在所描述的示例中,我们没有这个问题,但是如果我们有多个写入,则可能会遇到内存排序问题。易失性不是围栏,它不会强制内存排序,它只是阻止编译器优化。
那么,为什么这么多人使用挥发性布尔值来忙碌等待,它真的是便携式的吗?
这篇文章并没有说volatile
就是你所需要的(事实上,它不是),只是说它可以有用。
如果您这样做,并且如果您使用简单的泛型组件
LockingPtr
,则可以编写线程安全代码,并且不必担心竞争条件,因为编译器会为您担心并努力指出您错误的地方。
我真的不明白它是如何工作的。
它依赖于两个假设:
- 对布尔变量的读取和写入是原子的;
- 所有线程都具有统一的内存视图,因此在一个线程上所做的修改将在短时间内对其他线程可见,而不会有明确的内存屏障。
第一种可能会保留任何理智的架构。第二种适用于任何单核架构,以及目前广泛使用的多核架构,但不能保证它将来会继续存在。
上面的代码可以通过使用 C++11 安全地重写
std::atomic
今天,它可以而且应该如此。在2001年,当这篇文章写出来时,并没有那么多。
如果我们有多个写入,我们可能会遇到内存排序问题
事实上。如果此机制用于与其他数据同步,那么我们依赖于第三个假设:保留修改顺序。同样,大多数流行的处理器都会提供这种行为,但不能保证这种情况会继续下去。
为什么这么多人使用挥发性布尔值来忙碌等待
因为他们不能或不会改变他们在获得多线程内存模型之前形成的习惯C++。
它真的是便携式的吗?
不。C++11 内存模型并不能保证任何这些假设,随着典型内核数量的增加,它们很有可能对于未来的硬件支持变得不切实际。 volatile
从来都不是线程同步的解决方案,现在语言确实提供了正确的解决方案,这加倍了。
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 如何让LLDB在成功时退出,在失败时等待
- 等待整个 omp 块完成,然后再调用第二个函数
- 提升 ASIO - io_service 不要等待连接到线程
- 如何在C++中实现带有packaged_task的异步等待循环?
- 虚假唤醒是否会解锁所有等待线程,甚至是不相关的线程?
- 如何等待窗口隐藏在Qt中?
- 如何在不等待检索的情况下获取C++中的内存位置?
- 等待被迷住了,没有回来
- 等待 WaitForMultipleObjects 窗口中的事件数量可变
- 一个线程等待多个线程事件
- 等待 qthread 终止的正确方法是什么?
- 不可预测的C++睡眠/等待行为
- Bison/flex 在识别规则后等待输入
- 使用记事本C++打开 txt 文件时无需等待
- 接受函数在发送数据包时等待
- 在Visual Studio中运行/调试C ++时,如何在结束时等待输入
- 对于等待以 std::future wait() 返回的函数的 CPU 使用率或检查标志在循环中休眠一段时间哪个更好?
- 在等待时破坏condition_variable
- 等待() 等待进程是否消耗系统 CPU