Что такое SpinLock (спинлок) в многопоточности?

«Что такое SpinLock (спинлок) в многопоточности?» — вопрос из категории Многопоточность, который задают на 34% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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, который эффективнее для блокировок средней и большой длительности, так как передаёт управление планировщику ОС.