Я смотрел на compiler output of rmw atomics from gcc и заметил что-то странное - на Aarch64 операции rmw, такие как fetch_add, могут быть частично переупорядочены с расслабленными нагрузками.Частичное переупорядочение C++ 11 atomics на Aarch64
На Aarch64, следующий код может быть сгенерирован для value.fetch_add(1, seq_cst)
.L1:
ldaxr x1, [x0]
add x1, x1, 1
stlxr w2, x1, [x0]
cbnz L1
Однако, это возможно для нагрузок и магазинов, которые происходят до ldaxr быть заказано мимо нагрузки и нагрузки/магазинов, которые происходят после stlxr (см. here). GCC не добавляет заборы, чтобы предотвратить это - Вот небольшой фрагмент кода демонстрирует это:
void partial_reorder(std::atomic<uint64_t> loader, std::atomic<uint64_t> adder) {
loader.load(std::memory_order_relaxed); // can be reordered past the ldaxr
adder.fetch_add(1, std::memory_order_seq_cst);
loader.load(std::memory_order_relaxed); // can be reordered past the stlxr
}
генерации
partial_reorder(std::atomic<int>, std::atomic<int>):
ldr w2, [x0] @ reordered down
.L2:
ldaxr w2, [x1]
add w2, w2, 1
stlxr w3, w2, [x1]
cbnz w3, .L2
ldr w0, [x0] @ reordered up
ret
В действительности нагрузки могут быть частично заказана с операцией RMW - они происходят в середине его.
Итак, что общего? Что я спрашиваю?
Кажется странным, что атомная операция делится как таковая. Я не мог найти ничего в стандарте, предотвращающего это, но я считал, что существует комбинация правил, которые подразумевают, что операции неделимы.
Кажется, что это не относится к приобретению заказа. Если я выполняю нагрузку сразу после этой операции, я могу видеть переупорядочение хранилища или загрузки хранилища между fetch_add и более поздней операцией, что означает, что более поздний доступ к памяти, по меньшей мере, частично переупорядочен за операцией получения. Опять же, я не мог найти ничего в стандартах, явно заявляя, что это запрещено, а приобретать - упорядочение загрузки, но я понимаю, что операция получения применяется ко всей операции, а не только ее части. Аналогичный сценарий может применяться к выпуску, когда что-то переупорядочивается за ldaxr.
Это может быть несколько более растягивающее определения порядка, но кажется недействительным, что две операции до и после операции seq_cst могут быть переупорядочены друг за другом. Это может произойти (?), Если граничные операции переупорядочиваются в середине операции, а затем проходят один за другим.
Возможно, связано: http://bigflake.com/seq_cst.cpp показывает выход компилятора для x64/arm32/aarch64 для базовой атомной загрузки/хранения. 'store (val, std :: memory_order_seq_cst)', кажется, отсутствует барьер. Это с gcc 4.9 на Android. – fadden