C++11 Atomic memory order with non-atomic variables

…衆ロ難τιáo~ 提交于 2019-12-12 08:07:52

问题


I am unsure about how the memory ordering guarantees of atomic variables in c++11 affect operations to other memory.

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. Is it guaranteed that the effects of d = value; will not be seen before effects of a = version;, and will be seen before the effects of 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;
}

回答1:


Is it guaranteed that the effects of d = value; will not be seen before effects of a = version;, and will be seen before the effects of b = version;?

Yes, it is. This is because sequensial consistency barrier is implied when read or write atomic<> variable.

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:

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




回答2:


The rule is that, given a write thread that executes once, and nothing else that modifies a, b or d,

  • You can read a and b from a different thread at any time, and
  • if you read b and see version stored in it, then
    • You can read d; and
    • What you read will be 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).




回答3:


Your object d is written and read by two threads and it's not atomic. This is unsafe, as suggested in the C++ standard on multithreading:

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/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. 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:

  • the order of the d read compared to the d write can't be unfortunate if the two atomics are equal.
  • 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.



来源:https://stackoverflow.com/questions/30490696/c11-atomic-memory-order-with-non-atomic-variables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!