Created
April 14, 2018 20:31
-
-
Save RedBeard0531/5c24dbfcca71e7b611ecb3d504c7588b to your computer and use it in GitHub Desktop.
Examples of broken release sequences
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum State {INIT, PHASE2, DONE}; | |
std::atomic<State> state{INIT}; | |
int non_atomic = 0; // placeholder for actual data. | |
auto phase1 = std::thread([&] { | |
non_atomic = 1; | |
state.store(PHASE2, std::memory_order_release); | |
auto phase2 = std::thread([&] { | |
// Note that the store of PHASE2 inter-thread | |
// happens before the store of DONE because of | |
// http://eel.is/c++draft/thread.thread.constr#6 | |
state.store(DONE, std::memory_order_relaxed); | |
}); | |
// Do stuff. | |
phase2.join(); | |
}); | |
auto consumer = std::thread([&] { | |
while (state.load(std::memory_order_acquire) < PHASE2) {} | |
assert(non_atomic == 1); // This is a race today! | |
}); | |
consumer.join(); | |
phase1.join(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum State {INIT, PHASE2, PHASE3, DONE}; | |
std::atomic<State> state{INIT}; | |
int non_atomic = 0; // placeholder for actual data. | |
std::mutex mx; | |
std::condition_variable cv; | |
auto phase1 = std::thread([&] { | |
non_atomic = 1; | |
std::unique_lock lk(mx); | |
state.store(PHASE2, std::memory_order_release); | |
cv.notify_all(); | |
}); | |
auto phase2 = std::thread([&] { | |
std::unique_lock lk(mx); | |
// relaxed is safe here because the mutex synchronizes the phases | |
cv.wait(lk, [&] { | |
return state.load(std::memory_order_relaxed) == PHASE2; | |
}); | |
// Do stuff. | |
state.store(PHASE3, std::memory_order_relaxed); | |
cv.notify_all(); | |
}); | |
auto phase3 = std::thread([&] { | |
std::unique_lock lk(mx); | |
cv.wait(lk, [&] { | |
return state.load(std::memory_order_relaxed) == PHASE3; | |
}); | |
// Do stuff, then release final result. | |
state.store(DONE, std::memory_order_release); | |
cv.notify_all(); | |
}); | |
auto consumer = std::thread([&] { | |
while (state.load(std::memory_order_acquire) < PHASE2) {} | |
assert(non_atomic == 1); // This is a race today! | |
}); | |
consumer.join(); | |
phase1.join(); | |
phase2.join(); | |
phase3.join(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment