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

时间:2015-05-27 18:45:30

标签: c++ multithreading c++11 atomic memory-barriers

我不确定c ++ 11中原子变量的内存排序保证如何影响对其他内存的操作。

假设我有一个线程周期性地调用write函数来更新一个值,另一个线程调用read来获取当前值。是否保证在d = value;的影响之前不会看到a = 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;
}

3 个答案:

答案 0 :(得分:3)

规则是,给定BroadcastReceiver个执行一次的线程,而不修改writeab

  • 您可以随时从其他帖子中阅读da
  • 如果您阅读b并查看其中存储的b,那么
    • 您可以阅读version;和
    • 您阅读的内容为d

注意第二部分是否为真取决于内存排序;默认值为value)。

答案 1 :(得分:2)

您的对象d由两个线程编写和读取,并且它不是原子的。这是不安全的,如多线程的C ++标准所示:

  

1.10 / 4 如果其中一个修改了内存位置而另一个访问或修改了相同的内存位置,则两个表达式评估会发生冲突。

     

1.10 / 21 如果一个程序的执行在不同的线程中包含两个冲突的动作,则至少有一个   这不是原子的,也不会发生在另一个之前。任何这样的   数据竞争导致未定义的行为。

重要编辑:

在非原子的情况下,你无法保证阅读和写作之间的顺序。你甚至不能保证读者会读取作者写的值(这个short article explains the risk用于非原子变量)。

然而 ,您的读者循环基于对周围原子变量的测试而完成,对此有强有力的保证。假设version从不在编写者的不同调用之间重复,并且给出了获取其值的相反顺序:

  • 如果两个原子相等,d读取与d写入相比的顺序可能是不幸的。
  • 同样,如果两个原子相等,读取值也不一致。

这意味着如果你的非原子的不利竞争条件,由于循环,你最终会读到最后一个value

答案 2 :(得分:1)

  

是否可以保证在d = value;的影响之前不会看到a = version;的效果,并且会在b = version;的影响之前看到效果?

是的,确实如此。这是因为在读取或写入atomic<>变量时隐含顺序一致性障碍

不是在修改值之前及之后将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;
}

这在Linux内核中称为 seqlock http://en.wikipedia.org/wiki/Seqlock