可以使用std :: atomic内存屏障来在线程之间传输非原子数据吗? [英] Can std::atomic memory barriers be used to transfer non-atomic data between threads?

查看:402
本文介绍了可以使用std :: atomic内存屏障来在线程之间传输非原子数据吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码标准是否符合? (或者可以使其不符合 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 (see std::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 tagged memory_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆