Ответ
SpinLock (блокировка с активным ожиданием) — это низкоуровневый примитив синхронизации, в котором поток, не сумевший захватить блокировку, не переходит в состояние ожидания ядра ОС, а продолжает активно опрашивать ("крутиться" в цикле) флаг доступности.
Когда использовать:
- Короткие критические секции (несколько десятков или сотен инструкций).
- Минимизация накладных расходов на переключение контекста, когда время ожидания предположительно мало.
- В системном программировании, при реализации собственных примитивов или в ядре ОС.
Недостатки:
- Потребление процессорного времени: Поток в цикле ожидания занимает ядро ЦП (busy-waiting).
- Неэффективность: При длительном ожидании бесполезно тратит процессорные такты.
Реализация на C++ с использованием std::atomic_flag:
#include <atomic>
class SpinLock {
std::atomic_flag lock_flag = ATOMIC_FLAG_INIT;
public:
void lock() {
// test_and_set() атомарно устанавливает флаг в true и возвращает предыдущее значение.
// Цикл продолжается, пока предыдущее значение было true (заблокировано).
while (lock_flag.test_and_set(std::memory_order_acquire)) {
// На многих архитекциях полезно дать подсказку процессору,
// что это цикл ожидания (может снизить энергопотребление/конфликт шины).
// __builtin_ia32_pause(); // Для x86
}
}
void unlock() {
// Атомарно сбрасываем флаг, разрешая другим потокам захватить блокировку.
lock_flag.clear(std::memory_order_release);
}
};
// Использование
SpinLock my_lock;
int shared_data = 0;
void thread_function() {
my_lock.lock();
++shared_data; // Критическая секция
my_lock.unlock();
}
На практике в пользовательском коде чаще используют std::mutex, который эффективнее для блокировок средней и большой длительности, так как передаёт управление планировщику ОС.