#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");
}
This is an example from the CppCon talk https://www.youtube.com/watch?v=F6Ipn7gCOsY&ab_channel=CppCon (min 17)
The objective is to first print Hello from A
then allow threadB
to start. It is clear that busy waiting should be avoided because it uses a lot of CPU.
The author said that the while (!ready) {}
loop can be optimized (by putting the value of ready
into a register) by the compiler because the compiler sees that threadB
never sleeps so ready
could never be changed. But even if the thread never sleeps another thread could still change the value, right? There is no data race because ready
is atomic. The author states that this code is UB. Can somebody explain why the compiler is allowed to do such an optimization?
std::atomic
is that it can in fact change spontaneously, and the compiler cannot assume otherwise. Removing the loop will very much change the observable behavior of the program, hence not a valid optimization. – Allerasready.load()
– Alleras