我有以下代码在调试版本中工作,而不是在启用了g ++优化的版本构建中。 (当我说工作时,我的意思是当主线程将标志停止设置为true时,循环线程存在)。我知道可以通过添加volatile关键字来修复此问题。然而,我的问题是要了解在这种情况下究竟发生了什么。这是代码:
void main() {
bool stop = false;
std::thread reader_thread;
auto reader = [&]() {
std::cout << "starting reader" << std::endl;
//BindToCPU(reader_thread, 0);
while(!stop) {
}
std::cout << "exiting reader" << std::endl;
};
reader_thread = std::thread(reader);
sleep(2);
stop = true;
std::cout << "stopped" << std::endl;
reader_thread.join();
}
为什么会这样?是因为编译器优化吗?或者是因为缓存一致性问题?关于底下究竟发生了什么的一些细节值得赞赏。
答案 0 :(得分:3)
程序的行为未定义。问题是两个线程都访问名为stop
的变量,其中一个正在写入它。在C ++标准中,这是数据争用的定义,结果是未定义的行为。要摆脱数据竞争,您必须以某种形式引入同步。最简单的方法是将stop
的类型从bool
更改为std::atomic<bool>
。或者,您可以使用互斥锁,但对于此特定示例,这将是过度杀伤。
将stop
标记为volatile
可能会使症状消失,但不能解决问题。
答案 1 :(得分:2)
问题在于编译器,特别是优化阶段无法判断程序实际上是做了什么。特别是,它不能说“停止”可以是除了假之外的任何东西。最好和最简单的解决方案是使“停止”原子。这是更正的程序,额外收费的“睡眠”程序。
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
inline void std_sleep(long double seconds) noexcept
{
using duration_t = std::chrono::duration<long long, std::nano>;
const auto duration = duration_t(static_cast<long long> (seconds * 1e9));
std::this_thread::sleep_for(duration);
}
int main() {
std::atomic<bool> stop = false;
std::thread reader_thread;
auto reader = [&stop]() {
std::cout << "starting reader" << std::endl;
//BindToCPU(reader_thread, 0);
while(!stop) {
std_sleep(.25);
}
std::cout << "exiting reader" << std::endl;
};
reader_thread = std::thread(reader);
std_sleep(2.0);
stop = true;
std::cout << "stopped" << std::endl;
reader_thread.join();
return 0;
}
答案 2 :(得分:1)