Рассмотрим следующую реализацию 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: У блокировок спинов всегда требуется барьер памяти? Вращается ли на барьер памяти дорого?
-
В: Ожидаете ли вы, что будущие поколения процессоров не являются кеш-когерентными?