以下代码标准是否合规? (或者可以在不使x
原子或volatile
?)
这与an earlier question类似,但我想引用C ++标准的相关部分。
我担心的是,原子store()
和load()
没有为非原子变量(下例中的x
)提供足够的编译器障碍,以便正确释放和获取语义。
我的目标是实现无锁原语,例如队列,可以在线程之间传递指向常规C ++数据结构的指针。
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
int x; // regular variable, could be a complex data structure
std::atomic<int> flag { 0 };
void writer_thread() {
x = 42;
// release value x to reader thread
flag.store(1, std::memory_order_release);
}
bool poll() {
return (flag.load(std::memory_order_acquire) == 1);
}
int main() {
x = 0;
std::thread t(writer_thread);
// "reader thread" ...
// sleep-wait is just for the test.
// production code calls poll() at specific points
while (!poll())
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::cout << x << std::endl;
t.join();
}
答案 0 :(得分:6)
获得/释放,是的,这就足够了。相关引号(来自cppreference - 与大多数情况下的标准一样好):
内存模型
当表达式的评估写入内存位置而另一个评估读取或修改相同的内存位置时,表达式会发生冲突。除非
,否则具有两个冲突评估的程序会进行数据竞争
两个冲突的评估都是原子操作(见std::atomic
)- 其中一项冲突的评估发生在之前(参见
std::memory_order
)的std :: memory_order
发布 - 获取订购
如果线程A中的原子存储被标记为
memory_order_release
并且来自同一变量的线程B中的原子加载被标记为memory_order_acquire
,则所有内存写入(非原子和放松原子)发生 - 从线程A的角度来看,在原子存储之前,在线程B中成为可见的副作用,也就是说,一旦原子加载完成,线程B就保证看到线程A写入内存的所有内容。强>