C ++ 11 Order of atomic memory with non-atomic variables

I'm not sure how the guarantees of memory ordering of atomic variables in C ++ 11 affect operations in another memory.

Let's say I have one thread that periodically calls the write function to update the value, and another thread that calls read to get the current value. Are the effects guaranteed d = value; will not be visible before effects a = version; and will be visible before the effects 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; } 
+5
source share
3 answers

Are the effects guaranteed d = value; will not be visible before effects a = version; and will be visible before the effects b = version; ?

Yes it is. This is because when reading or writing an atomic<> variable, a sequence sequence barrier is implied.

Instead of saving the version tag in two atomic variables before and after modifying the value, you can increase the single atomic variable before and after the 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 called seqlock in the Linux kernel: http://en.wikipedia.org/wiki/Seqlock

+1
source

The rule is that with a given write thread that runs once, and nothing else changes a , b or d ,

  • You can read a and b from another stream at any time and
  • if you read b and see the version stored in it, then
    • You can read d ; and
    • What you read will be value .

Note that if the second part is true, it depends on the memory ordering; this is true by default ( memory_order_seq_cst ).

+3
source

Your object d written and read by two streams and is not atomic. This is not safe, as suggested in the C ++ standard for multithreading:

1.10 / 4 . Two evaluations of expressions contradict each other if one of them changes the location of the memory, and the other - or changes the same memory cell.

1.10 / 21 A program execution contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and does not occur before the other. Any such data guest leads to undefined behavior.

Important change:

In your non-nuclear case, you have no guarantees regarding the order between reading and writing. You do not even have a guarantee that the reader will read the value written by the author (this short article explains the risk for non-atomic variables).

However , your reader cycle ends by checking the surrounding atomic variables for which strong guarantees exist. Assuming that version never repeated between different calls to the writer and the reverse order is set in which you acquire your meaning:

  • the reading order of d compared to writing d cannot be unsuccessful if the two atoms are equal.
  • likewise, the reading value cannot be inconsistent if the two atoms are equal.

This means that in case of an unfavorable race condition on your non-atomic, thanks to the loop, you will finish reading the last value .

+2
source

All Articles