简体   繁体   English

C ++ 11使用非原子变量的原子内存顺序

[英]C++11 Atomic memory order with non-atomic variables

I am unsure about how the memory ordering guarantees of atomic variables in c++11 affect operations to other memory. 我不确定c ++ 11中的原子变量的内存排序保证如何影响对其他内存的操作。

Let's say I have one thread which periodically calls the write function to update a value, and another thread which calls read to get the current value. 假设我有一个线程周期性地调用write函数来更新一个值,另一个线程调用read来获取当前值。 Is it guaranteed that the effects of d = value; 是否保证d = value;的影响d = value; will not be seen before effects of a = version; a = version;效果之前不会被看到a = version; , and will be seen before the effects of b = version; ,并且会在b = version;的影响之前看到b = version; ?

atomic<int> a {0};
atomic<int> b {0};
double d;

void write(int version, double value) {
    a = version;
    d = value;
    b = version;
}

double read() {
    int x,y;
    double ret;
    do {
        x = b;
        ret = d;
        y = a;
    } while (x != y);
    return ret;
}

Your object d is written and read by two threads and it's not atomic. 您的对象d由两个线程写入和读取,并且它不是原子的。 This is unsafe, as suggested in the C++ standard on multithreading: 这是不安全的,如多线程的C ++标准所示:

1.10/4 Two expression evaluations conflict if one of them modifies a memory location and the other one accesses or modifies the same memory location. 1.10 / 4如果其中一个修改了内存位置而另一个访问或修改了相同的内存位置,则两个表达式评估会发生冲突。

1.10/21 The execution of a program contains a data race if it contains two conflicting actions in different threads,at least one of which is not atomic, and neither happens before the other. 1.10 / 21程序的执行包含数据竞争,如果它在不同的线程中包含两个冲突的动作,其中至少有一个不是原子的,并且都不会发生在另一个之前。 Any such data race results in undefined behavior. 任何此类数据争用都会导致未定义的行为。

Important edit: 重要编辑:

In your non-atomic case, you have no guarantees about the ordering between the reading and the writing. 在非原子的情况下,你无法保证阅读和写作之间的顺序。 You don't even have guarantee that the reader will read a value that was written by the writer (this short article explains the risk for non-atomic variables). 您甚至不能保证读者会读取作者写的值(这篇简短的文章解释了非原子变量的风险 )。

Nevertheless , your reader's loop finishes based on a test of the surrounding atomic variables, for which there are strong guarantees. 然而 ,读者的循环基于对周围原子变量的测试而完成,对此有很强的保证。 Assuming that version never repeats between writer different calls, and given the reverse order in which you aquire their value: 假设version从不在编写者不同的调用之间重复,并且给出了获取其值的相反顺序:

  • the order of the d read compared to the d write can't be unfortunate if the two atomics are equal. 如果两个原子相等,则与d写相比, d读的顺序不可能是不幸的。
  • similarly, the read value can't be inconsistent if the two atomics are equal. 类似地,如果两个原子相等,则读取值不能不一致。

This means that in case of an adverse race condition on your non-atomic, thanks to the loop, you'll end-up reading the last value . 这意味着如果你的非原子的不利竞争条件,由于循环,你将最终读取最后一个value

The rule is that, given a write thread that executes once, and nothing else that modifies a , b or d , 规则是,给定一个执行一次的write线程,没有其他任何修改abd

  • You can read a and b from a different thread at any time, and 您可以随时从不同的线程中读取ab
  • if you read b and see version stored in it, then 如果您阅读b并查看存储在其中的version ,那么
    • You can read d ; 你可以读d ; and
    • What you read will be value . 你读到的将是value

Note that whether the second part is true depends on the memory ordering; 注意第二部分是否为真取决于内存排序; it is true with the default one ( memory_order_seq_cst ). 它与默认值( memory_order_seq_cst )一样。

Is it guaranteed that the effects of d = value; 是否保证d = value;的影响d = value; will not be seen before effects of a = version; a = version;效果之前不会被看到a = version; , and will be seen before the effects of b = version; ,并且会在b = version;的影响之前看到b = version; ?

Yes, it is. 是的。 This is because sequensial consistency barrier is implied when read or write atomic<> variable. 这是因为在读取或写入atomic<>变量时隐含了顺序一致性障碍

Instead of storing version tag into two atomic variables before value's modification and after it, you can increment single atomic variable before and after modification: 不是在修改值之前和之后将version标记存储到两个原子变量中,而是可以在修改之前和之后增加单个原子变量:

atomic<int> a = {0};
double d;

void write(double value)
{
     a = a + 1; // 'a' become odd
     d = value; //or other modification of protected value(s)
     a = a + 1; // 'a' become even, but not equal to the one before modification
}

double read(void)
{
     int x;
     double ret;
     do
     {
         x = a;
         ret = value; // or other action with protected value(s)
     } while((x & 2) || (x != a));
     return ret;
}

This is known as seqlock in the Linux kernel: http://en.wikipedia.org/wiki/Seqlock 这在Linux内核中称为seqlockhttp//en.wikipedia.org/wiki/Seqlock

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在C11 / C ++ 11中,可以在同一个内存中混合原子/非原子操作吗? - In C11/C++11, possible to mix atomic/non-atomic ops on the same memory? 标准C ++ 11是否保证memory_order_seq_cst阻止StoreLoad在原子周围重新排序非原子? - Does standard C++11 guarantee that memory_order_seq_cst prevents StoreLoad reordering of non-atomic around an atomic? 在C ++ 11和OpenMP中以原子方式访问非原子内存位置? - Atomic access to non-atomic memory location in C++11 and OpenMP? 在c ++ 11中,可以使用std :: atomic在两个线程之间传输非原子数据 - in c++11, can std::atomic be used to transmit non-atomic data between two thread C++11 原子:std::memory_order 代码是否可移植? - C++11 atomic: is std::memory_order code portable? C ++ 11如何在atomic :: store和atomic :: load中观察内存顺序 - C++11 how to observe memory order in atomic::store and atomic::load 如何在 C++ 中混合原子和非原子操作? - How to mix atomic and non-atomic operations in C++? 访问C ++ 0x的原子<int>为非原子 - Accessing atomic<int> of C++0x as non-atomic c ++ 11原子排序:锁的扩展总命令memory_order_seq_cst - c++11 atomic ordering: extended total order memory_order_seq_cst for locks MOV x86指令是否实现了C ++ 11 memory_order_release原子存储? - Does the MOV x86 instruction implement a C++11 memory_order_release atomic store?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM