Ich kämpfe darum, die Standardse in Bezug auf memory_order_seq_cst Garantien zu verstehen, und ich kann kein geeignetes Beispiel finden.
Der folgende Code zeigt meine Situation.
Code: Select all
#include
#include
#include
void race_test() {
std::atomic data = 0;
std::atomic_bool flag = false;
constexpr std::size_t REP_COUNT = 1000;
std::thread inc_thread{[&] {
for (std::size_t i = 0; i != REP_COUNT; ++i) {
data.fetch_add(1, std::memory_order_relaxed);
flag.store(true, std::memory_order_release);
flag.notify_one();
}
}};
std::thread dec_thread{[&] {
for (std::size_t i = 0; i != REP_COUNT; ++i) {
while (data.load(std::memory_order_relaxed) == 0) {
flag.wait(false, std::memory_order_acquire);
flag.store(false, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
}
data.fetch_sub(1, std::memory_order_relaxed);
}
}};
inc_thread.join();
dec_thread.join();
}
int main()
{
for (std::size_t i = 0; i != 1000; ++i)
race_test();
}
Idealerweise inc_thread Inkrementiert Daten Dann legt Flag fest und benachrichtigt dec_thread .
wartet darauf, dass Flag festgelegt wird, während Data ungleich Null ist, dann die Daten und löscht Flag . Benachrichtigt den Verbraucher -Thread, alle verfügbaren Daten zu verarbeiten. Es ist beabsichtigt, dass inc_thread möglicherweise "voraus" von dec_thread "ausgeführt" kann. Das Ziel ist nur, dass die Daten nach der Herstellung rechtzeitig konsumiert werden. Ich habe gerade die Daten hier zu einer Atomnotik gemacht, da es für die Demonstration ausreichte. /> Ich kann mir vorstellen, dass dies geschieht, weil das Flag von dec_thread zwischen inc_thread s Flag.Store (true) und flag.notify_one () effektiv das nächste Benachrichtigung erfolgt. std :: atomic_thread_fence (std :: memory_order_seq_cst) verhindert die Neuordnung von Flag.Store (Falsch) und data.load () und ich kann sehen, wie das die Deadlock
verhindern würde, aber warum nicht std :: atomic_thead_thead_fence (std :: minese_order_order_rel)