Я изучаю алгоритмы Деккера, просматривая код из этого блога и код выглядит следующим образом:
std::atomic<bool> flag0(false),flag1(false);
std::atomic<int> turn(0);
void p0()
{
flag0.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
while (flag1.load(std::memory_order_relaxed))
{
if (turn.load(std::memory_order_relaxed) != 0)
{
flag0.store(false,std::memory_order_relaxed);
// --------------------------------------------------------------------
// Is it need to add a memory fence here to prevent storing `false` to flag0 from
// reordering after the while loop waiting for turn?
// ---------------------------------------------------------------------
while (turn.load(std::memory_order_relaxed) != 0)
{
}
//
// Any chances flag0.store() be reordered here ?
//
flag0.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
}
}
std::atomic_thread_fence(std::memory_order_acquire);
// critical section
turn.store(1,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
flag0.store(false,std::memory_order_relaxed);
}
void p1()
{
flag1.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
while (flag0.load(std::memory_order_relaxed))
{
if (turn.load(std::memory_order_relaxed) != 1)
{
flag1.store(false,std::memory_order_relaxed);
// --------------------------------------------------------------------
// Is it need to add a memory fence here to prevent storing `false` to flag0 from
// reordering after the while loop waiting for turn?
// ---------------------------------------------------------------------
while (turn.load(std::memory_order_relaxed) != 1)
{
}
//
// Any chances flag1.store() be reordered here ?
//
flag1.store(true,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
}
}
std::atomic_thread_fence(std::memory_order_acquire);
// critical section
turn.store(0,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
flag1.store(false,std::memory_order_relaxed);
}
Необходимо ли добавить некоторый забор памяти между
flag0.store(false,std::memory_order_relaxed);
И
while (turn.load(std::memory_order_relaxed) != 0) {}
?
Я не уверен, есть ли вероятность того, что компилятор переупорядочит сохранение в flag0
и пока l oop в ожидании turn
. Если это так, то в случае, когда поток 0 и поток 1 вводят p0 и p1, соответственно, с flag0 и flag1, установленными в true, одновременно, поток 0 может зависать при ожидании установки flag1
на false, а поток 1 может зависать ожидание бесконечной установки turn
на 1, что приводит к мертвой блокировке.