How std :: memory_order_seq_cst works

I gave an example about std :: memory_order_seq_cst: http://en.cppreference.com/w/cpp/atomic/memory_order

#include <thread> #include <atomic> #include <cassert> std::atomic<bool> x = {false}; std::atomic<bool> y = {false}; std::atomic<int> z = {0}; void write_x() { x.store(true, std::memory_order_seq_cst); } void write_y() { y.store(true, std::memory_order_seq_cst); } void read_x_then_y() { while (!x.load(std::memory_order_seq_cst)) ; if (y.load(std::memory_order_seq_cst)) { ++z; } } void read_y_then_x() { while (!y.load(std::memory_order_seq_cst)) ; if (x.load(std::memory_order_seq_cst)) { ++z; } } int main() { std::thread a(write_x); std::thread b(write_y); std::thread c(read_x_then_y); std::thread d(read_y_then_x); a.join(); b.join(); c.join(); d.join(); assert(z.load() != 0); // will never happen } 

This example is also mentioned in the Acquisition / Issue issue compared to sequential sequential memory order .

My question is, how is it possible that thread c and thread d see different things? If possible, why does this simple example below always give z = 3? For example, stream b might say "ok, I see 0, although stream a is already done, so z becomes 0 + 1 again"

 #include <atomic> #include <iostream> std::atomic<int> z = {0}; void increment() { z.fetch_add(1, std::memory_order_relaxed); } int main() { std::thread a(increment); std::thread b(increment); std::thread c(increment); a.join(); b.join(); c.join(); std::cout << z.load() << '\n'; } 
+5
source share
2 answers

So, seeing different things in your comment, you mean that Thread C see x == 1, y == 0 and Thread D see x == 0 and y == 1. Is this possible with consistent consistency?

Suppose this complete order (modification is a transition between these symbolized states of memory):

 {x==0,y==0} : S0 {x==1,y==0} : S1 {x==1,y==1} : S2 

When we say β€œsee,” we mean that the potential of the flow fulfills the load. Two loads cannot be executed simultaneously in the same thread. So, how is it possible that thread C sees x == 1 and then sees y == 0 and Thread D sees x == 0 and then sees y == 1? Thread C performs two loads, while memory is in state S1, and in thread D they see x in state S0, and then see y in state S2.

In your code example, what happens is that Thread C load x then loads y, and Thread D loads y again until it is true, and then load x. Thus, after y == 1, this ensures that x==1 in that complete order.

As Mine said in his comment, nothing could have been expected if instead of using a sequence of sequential sequences, the memory retrieval / release order was used: the retrieval / release semantics does not imply any sort of full ordering, moreover, it does not occur before the relationship between the storage to x , and the storage is y . Thus, the statement z.load()!=0 can be satisfied.

+1
source

Because read-modify-write operations have special guarantees.

In accordance with the standard [atomics.order], clause 11 :

Atomic read-modify-write operations should always read the last value (in the modification order) written before the write associated with the read-modify-write operation.

+3
source

Source: https://habr.com/ru/post/1275562/


All Articles