【发布时间】:2021-10-28 05:57:32
【问题描述】:
#include <iostream>
#include <thread>
#include <mutex>
int main()
{
std::atomic<bool> ready = false;
std::thread threadB = std::thread([&]() {
while (!ready) {}
printf("Hello from B\n");
});
std::this_thread::sleep_for(std::chrono::seconds(1));
printf("Hello from A\n");
ready = true;
threadB.join();
printf("Hello again from A\n");
}
这是来自 CppCon 谈话 https://www.youtube.com/watch?v=F6Ipn7gCOsY&ab_channel=CppCon(分钟 17)的一个例子
目标是首先打印Hello from A,然后让threadB 启动。很明显,应该避免忙等待,因为它会占用大量 CPU。
作者说while (!ready) {} 循环可以由编译器优化(通过将ready 的值放入寄存器),因为编译器看到threadB 永远不会休眠,因此ready 永远不会被更改。但是即使线程从不休眠,另一个线程仍然可以改变值,对吧?没有数据竞争,因为ready 是原子的。作者声明这段代码是UB。有人能解释一下为什么允许编译器做这样的优化吗?
【问题讨论】:
-
我认为扬声器不正确,并且无法优化此循环。
std::atomic的全部意义在于它实际上可以自发改变,编译器不能假设其他情况。删除循环将极大地改变程序的可观察行为,因此不是有效的优化。 -
Sleep 告诉 CPU 在一定时间内不需要,仅此而已(与花费相同时间的逻辑没有区别),您的循环不会得到优化(已删除)除非它是空的。
-
@Top-Master 循环非为空 - 它调用
ready.load() -
我认为既然这里有两个选择(优化循环,不要优化循环),这将是一个问题,这是否是未指定的行为,而不是未定义的行为
-
最好将原子视为防止切片和排序。它们也不是隐式易变的。
标签: c++ multithreading compiler-optimization busy-waiting