Сбой синхронизации в стиле Dekker обычно объясняется переупорядочением инструкций. I.e, если мы пишем
atomic_int X;
atomic_int Y;
int r1, r2;
static void t1() {
X.store(1, std::memory_order_relaxed)
r1 = Y.load(std::memory_order_relaxed);
}
static void t2() {
Y.store(1, std::memory_order_relaxed)
r2 = X.load(std::memory_order_relaxed);
}
Затем нагрузки могут быть переупорядочены с помощью магазинов, что приведет к r1==r2==0
.
Я ожидал, что забор_объемки будет использоваться для предотвращения такого переупорядочения:
static void t1() {
X.store(1, std::memory_order_relaxed);
atomic_thread_fence(std::memory_order_acq_rel);
r1 = Y.load(std::memory_order_relaxed);
}
static void t2() {
Y.store(1, std::memory_order_relaxed);
atomic_thread_fence(std::memory_order_acq_rel);
r2 = X.load(std::memory_order_relaxed);
}
Нагрузка не может быть перемещена над ограждением, и магазин не может быть перемещен ниже забора, поэтому следует предотвратить плохой результат.
Однако эксперименты показывают, что r1==r2==0
все еще может возникать. Есть ли объяснение, основанное на переупорядочении? Где ошибка в моих рассуждениях?