简体   繁体   中英

How does memory_order_seq_cst synchronize with non-atomic operations?

If one uses a single atomic variable and std::memory_order_seq_cst , are non-atomic operations guaranteed not to be reordered?

For example, if I have

std::atomic<bool> quux = {false};

void foo() {
    bar();
    quux.store(true, std::memory_order_seq_cst);
    moo();
}

is bar() guaranteed not to get reordered after the call of store , and moo() not to get reordered before the call of store , as long as I use std::memory_order_seq_cst , at least from the perspective of another thread?

Or, to put it in code, are the following assumptions valid if run from another thread?

if(quux.load(std::memory_order_seq_cst) == true) {
   // bar guaranteed to be called; its side-effects are visible
   // moo might have been called, but is not guaranteed to
} else {
   // bar might have been called, but is not guaranteed to
   // moo might have been called, but is not guaranteed to
}

Note that I assume that neither bar nor moo use atomic operations, mutexes, locks, fences or other synchronization features.

According to the link http://en.cppreference.com/w/cpp/atomic/memory_order linked by @Maxim there is an error with regards of the memory_order_seq_cst.The text above is exchanged with memory_order_acq_rel. The text for memory_order_seq_cst:

memory_order_seq_cst: A load operation with this memory order performs an acquire operation, a store performs a release operation, and read-modify-write performs both an acquire operation and a release operation, plus a single total order exists in which all threads observe all modifications in the same order (see Sequentially-consistent ordering below)

So in your case the store operation is equivalent to a release which means that moo() can be reordered before the fence.

If one uses a single atomic variable and std::memory_order_seq_cst , are non-atomic operations guaranteed not to be reordered?

The standard is pretty clear on this http://en.cppreference.com/w/cpp/atomic/memory_order :

memory_order_seq_cst A load operation with this memory order performs an acquire operation, a store performs a release operation, and read-modify-write performs both an acquire operation and a release operation, plus a single total order exists in which all threads observe all modifications in the same order.

memory_order_acquire A load operation with this memory order performs the acquire operation on the affected memory location: no reads or writes in the current thread can be reordered before this load .

memory_order_release A store operation with this memory order performs the release operation: no reads or writes in the current thread can be reordered after this store .

In other words, no loads or stores (both non-atomic and atomic) can be reordered around memory_order_seq_cst operations.


is bar() guaranteed not to get reordered after the call of store, and moo() not to get reordered before the call of store, as long as I use std::memory_order_seq_cst, at least from the perspective of another thread?

If the definitions of bar and moo are not available in the current translation unit, the compiler assumes that these functions do memory loads and/or have side effects (do I/O or stores to memory), and hence cannot be reordered around memory_order_seq_cst operations.

If the definitions are available and the functions do not do I/O or memory loads/stores then they can be reordered. These would be pure functions or functions that do nothing and return void or a constant.

Because the strictest memory order is used, the functions bar and moo cannot be reordered past or before the store to quux respectively.

Your conclusion for the if-else case is not quite correct.

If the expression if(quux.load(std::memory_order_seq_cst) == true) evaluates to true, then the function bar will definitely already complete its call. The order of call to moo cannot be determined. It might have finished, not started or it could be in the middle of the call.

If the mentioned expression evaluates to false, then we cannot determine order for both functions. While it is true that at the moment the expression evaluates to false, the function moo hasn't been called yet, it might be called just after that, before the execution proceed to the else clause. Once in the else clause, the status of the function moo is the same as in the previous paragraph (it cannot be determined).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM