C++ 使用非原子布尔时的未定义行为

C++ 使用非原子布尔时的未定义行为,c++,windows,multithreading,visual-studio-2013,C++,Windows,Multithreading,Visual Studio 2013,当使用普通bool标志来控制一个线程停止它正在做的事情时,最糟糕的事情是什么?其特点是线程停止的确切时间一点也不重要,它只是播放一些媒体,甚至可能延迟半秒才做出反应。它有一个简单的while(!restart)循环: 另一个线程更改了一些seeting,然后将restart设置为true: someSetting = newSetting; restart = 1; 由于回放循环每秒运行数千次,我担心使用原子bool可能会增加延迟。我理解这是“未定义的行为”,但这是如何表现出来的呢?如果某个点

当使用普通bool标志来控制一个线程停止它正在做的事情时,最糟糕的事情是什么?其特点是线程停止的确切时间一点也不重要,它只是播放一些媒体,甚至可能延迟半秒才做出反应。它有一个简单的while(!restart)循环:

另一个线程更改了一些seeting,然后将restart设置为true:

someSetting = newSetting;
restart = 1;

由于回放循环每秒运行数千次,我担心使用原子bool可能会增加延迟。我理解这是“未定义的行为”,但这是如何表现出来的呢?如果某个点的bool是54r*wx]%,那又怎样?我可以得到运行时错误吗?bool最终会变成一个可理解的值,不是吗?(顺便说一句,代码目前可以工作。)在另一篇文章中,有人建议标志可能永远不会更改,因为线程有单独的缓存-这听起来很不确定,编译器肯定必须确保即使存在数据争用,共享变量也会更改?或者,控制线程的执行顺序可能会更改,并且在重新启动后某些设置可能会更改?同样,这听起来令人毛骨悚然,为什么编译器会允许这种情况发生


我曾经考虑过在循环中设置一个计数器,并且每一千次只检查一个原子布尔标志。但是我不想这样做,除非我真的必须这样做。

UB并不意味着你的代码不工作,它只是意味着你的代码的行为没有被标准指定。您必须使用
std::atomic
使您的代码符合标准,而不会实际更改行为。您可以使用
内存\u顺序\u relaxed
执行此操作:

atomic<int> restart ....

while (!restart.load(memory_order_relaxed))
{ 
    //do something
}

此代码将发出与您相同的指令。

可能发生的最坏情况是编译器将其转换为无限循环,或完全消除循环体。循环(和标志)目前可以工作,因此除非将来更改优化,否则这似乎不是问题。“bool最终会变成一个可理解的值,不是吗?”在当今流行的处理器上,是的。但不能保证这种情况会无限期地持续下去——硬件级缓存一致性不会随着处理器数量的增加而扩展。”当然,即使存在数据竞争,编译器也必须确保共享变量被更改?”-否。如果存在数据竞争,那么行为是未定义的。编译器知道它是“共享”的唯一方式“如果您这样说的话,通过使其原子化或以其他方式同步对它的访问。@bazza,只要您在Visual Studio上编译。而且它只是OK,因为Visual C++作为非标准扩展。这意味着它们与原子标志具有完全相同的性能影响(因为它们实际上具有完全相同的作用)。
atomic<int> restart ....

while (!restart.load(memory_order_relaxed))
{ 
    //do something
}
someSetting = newSetting;
restart.store(1, memory_order_relaxed);