Рассмотрим следующую реализацию spin_lock()
, первоначально из этого answer:
void spin_lock(volatile bool* lock) {
for (;;) {
// inserts an acquire memory barrier and a compiler barrier
if (!__atomic_test_and_set(lock, __ATOMIC_ACQUIRE))
return;
while (*lock) // no barriers; is it OK?
cpu_relax();
}
}
Что я уже знаю:
-
volatile
не позволяет компилятору оптимизировать out*lock
перечитывать на каждой итерации циклаwhile
; -
volatile
не вставляет ни памяти, ни ограничения компилятора; - такая реализация действительно работает в GCC для
x86
(например, в ядре Linux) и некоторых других архитектурах; - по крайней мере один барьер памяти и компилятора требуется в реализации
spin_lock()
для общей архитектуры; этот пример вставляет их в__atomic_test_and_set()
.
Вопросы:
-
Здесь
volatile
достаточно или существуют какие-либо архитектуры или компиляторы, где в циклеwhile
требуется защита памяти или компилятора или атомная операция?1.1 Согласно
C++
стандартам?1.2 На практике для известных архитектур и компиляторов, особенно для GCC и платформ, он поддерживает?
- Является ли эта реализация безопасной для всех архитектур, поддерживаемых GCC и Linux? (По крайней мере, это неэффективно на некоторых архитектурах, верно?)
- Безопасен ли цикл
while
в соответствии сC++11
и его моделью памяти?
Есть несколько связанных вопросов, но я не смог построить явный и однозначный ответ от них:
-
Q: Предел памяти в одном потоке
В принципе: Да, если выполнение программы перемещается от одного ядра к другому, возможно, он не увидит все записи, которые произошли в предыдущем ядре.
-
В значительной степени все современные архитектуры, кэши (например, кеши L1 и L2) обеспечены связными аппаратными средствами. Нет необходимости скрывать кеш, чтобы сделать память видимой для других ЦП.
-
Q: Является ли моя реализация блокировки спина правильной и оптимальной?
-
Q: У блокировок спинов всегда требуется барьер памяти? Вращается ли на барьер памяти дорого?
-
В: Ожидаете ли вы, что будущие поколения процессоров не являются кеш-когерентными?