考虑以下代码:
// global
std::atomic<bool> run = true;
// thread 1
while (run) { /* do stuff */ }
// thread 2
/* do stuff until it's time to shut down */
run = false;
我是否需要与原子变量相关的开销?我的直觉是,布尔变量的读/写无论如何都或多或少是原子的(这是常见的g ++ / Linux / Intel设置)并且如果有一些写/读时序怪异,并且我在线程1上的运行循环停止一个结果提前或结束,我对这个应用程序并不十分担心。
或者我在这里缺少一些其他考虑因素?看看perf,看来我的代码在std::atomic_bool::operator bool
中花费了相当多的时间,而我宁愿把它放在循环中。
答案 0 :(得分:11)
你需要使用std::atomic
来避免不希望的优化(编译器读取一次值并且总是循环或从不循环)并在没有强排序内存模型的系统上获得正确的行为(x86是强有序的,所以一旦写入完成,下一次读取将会看到它;在其他系统上,如果线程由于其他原因没有将CPU缓存刷新到主RAM,那么很长一段时间内可能看不到写入(如果有的话)。
你可以提高性能。默认使用std::atomic
使用a sequential consistency model,这对于单个标记值来说是过度杀伤。您可以使用load
/ store
使用明确(且不太严格)的内存排序来加快速度,因此每个load
都不需要使用最偏执的模式来保持一致性。
例如,你可以这样做:
// global
std::atomic<bool> run = true;
// thread 1
while (run.load(std::memory_order_acquire)) { /* do stuff */ }
// thread 2
/* do stuff until it's time to shut down */
run.store(false, std::memory_order_release);
在x86机器上,任何比(默认的,最严格的)顺序一致性排序更严格的排序通常最终不会做任何事情,只是确保指令按特定顺序执行;由于强有序的存储器模型,不需要总线锁定等。因此,除了保证值实际上是从内存中读取,而不是缓存到寄存器并重用,在x86上使用原子这种方式是免费的,而在非x86机器上,它使你的代码正确(否则它不会是)。