#include <assert.h>
#include <atomic>
#include <iostream>
#include <thread>
std::atomic_bool b(false);
std::atomic_bool lock{false};
void producer() {
b.store(true, std::memory_order_seq_cst);
lock.store(true, std::memory_order_seq_cst);
}
void consume() {
while (!lock.load(std::memory_order_seq_cst))
;
assert(b.load(std::memory_order_seq_cst));
b.store(false, std::memory_order_seq_cst);
lock.store(false, std::memory_order_seq_cst);
}
int main() {
std::thread t1([&]() {
while (true)
consume();
});
std::thread t2([&]() {
while (true)
producer();
});
t1.join();
t2.join();
}
Assert in consume should never fail, memory_order_seq_cst guarentee that atmoic operation run in the order that they are wrote;
But assert fail happened :(
CodePudding user response:
Your analysis would be correct for a single pair of produce()
and consume()
but not for an endless loop of them.
Thread 1 | Thread 2 |
---|---|
b.store(true, std::memory_order_seq_cst); |
|
lock.store(true, std::memory_order_seq_cst); |
|
while (!lock.load(std::memory_order_seq_cst)); |
|
assert(b.load(std::memory_order_seq_cst)); |
|
b.store(true, std::memory_order_seq_cst); |
|
b.store(false, std::memory_order_seq_cst); |
|
lock.store(false, std::memory_order_seq_cst); |
|
lock.store(true, std::memory_order_seq_cst); |
|
while (!lock.load(std::memory_order_seq_cst)); |
|
assert(b.load(std::memory_order_seq_cst)); Assert fires! |
The table shows an ordering where b
is false and lock
is true.
If you want that guarantee, you need to have produce
wait for lock
to be false.
void producer() {
while (lock.load(std::memory_order_seq_cst))
;
b.store(true, std::memory_order_seq_cst);
lock.store(true, std::memory_order_seq_cst);
}
CodePudding user response:
void producer() {
b.store(true, std::memory_order_seq_cst); // 1
lock.store(true, std::memory_order_seq_cst); // 2
}
void consume() {
while (!lock.load(std::memory_order_seq_cst))
; // 3
assert(b.load(std::memory_order_seq_cst)); // 4
b.store(false, std::memory_order_seq_cst); // 5
lock.store(false, std::memory_order_seq_cst); // 6
}
The following steps will make the assert fail: 1 -> 5 -> 6 -> 2 -> 3 -> 4