可以使用std :: atomic内存屏障来在线程之间传输非原子数据吗? [英] Can std::atomic memory barriers be used to transfer non-atomic data between threads?
问题描述
以下代码标准是否符合? (或者可以使其不符合 x
原子或 volatile
?)
这类似于早先的问题,但是我想引用C ++标准的相关部分。
我担心的是,原子 store()
和 load()
不为非原子变量提供足够的编译器障碍
我的目标是实现无锁的原语,如下面的例子中所示:$ c> x 作为队列,可以将指针传递到线程之间的常规C ++数据结构。
#include< atomic>
#include< chrono>
#include< iostream>
#include< thread>
int x; //正则变量,可能是一个复杂的数据结构
std :: atomic< int>标志{0};
void writer_thread(){
x = 42;
//向读取器线程释放值x
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只是为了测试。
//生产代码在特定点调用poll()
while(!poll())
std :: this_thread :: sleep_for(std :: chrono :: milliseconds 50));
std :: cout<< x<< std :: endl;
t.join();
}
,这就够了。相关引号(来自 cppreference —在大多数情况下与标准一样好):
内存模型
当表达式的求值写入内存位置,修改相同的内存位置,表达式被称为冲突。具有两个冲突评估的程序具有数据竞争,除非
两个冲突评估都是原子操作(参见std :: atomic
)
- 其中一个冲突评估 $ c> std :: memory_order )
std :: memory_order
发布 - 获取订单
如果线程A中的原子存储标记为
memory_order_release
来自同一变量的线程B中的原子负载被标记为memory_order_acquire
,从原点存储开始的所有内存写入(非原子和轻松原子)的线程A,在线程B中变为可见的副作用,即一旦原子加载完成,线程B就保证看到线程A写入存储器的所有内容。
Is the following code standards compliant? (or can it be made compliant without making x
atomic or volatile
?)
This is similar to an earlier question, however I would like a citation to the relevant section of the C++ standard, please.
My concern is that atomic store()
and load()
do not provide sufficient compiler barriers for the non-atomic variables (x
in the example below) to have correct release and acquire semantics.
My goal is to implement lock-free primitives, such as queues, that can transfer pointers to regular C++ data structures between threads.
#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();
}
With acquire/release, yes, this will be enough. Relevant quotes (from cppreference—as good as the standard in most cases):
Memory Model
When an evaluation of an expression writes to a memory location and another evaluation reads or modifies the same memory location, the expressions are said to conflict. A program that has two conflicting evaluations has a data race unless either
both conflicting evaluations are atomic operations (seestd::atomic
)- one of the conflicting evaluations happens-before another (see
std::memory_order
)std::memory_order
Release-Acquire ordering
If an atomic store in thread A is tagged
memory_order_release
and an atomic load in thread B from the same variable is taggedmemory_order_acquire
, all memory writes (non-atomic and relaxed atomic) that happened-before the atomic store from the point of view of thread A, become visible side-effects in thread B, that is, once the atomic load is completed, thread B is guaranteed to see everything thread A wrote to memory.
这篇关于可以使用std :: atomic内存屏障来在线程之间传输非原子数据吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!