Какие примитивы синхронизации вы знаете?

«Какие примитивы синхронизации вы знаете?» — вопрос из категории Алгоритмы и структуры данных, который задают на 28% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В контексте многопоточного программирования и конкурентного доступа к данным я работал со следующими примитивами синхронизации:

1. Мьютексы (Mutex) Базовый примитив для обеспечения взаимного исключения. Позволяет только одному потоку выполнять критическую секцию кода.

// Пример на C++
std::mutex mtx;
mtx.lock();
// Критическая секция — доступ к общему ресурсу
shared_variable++;
mtx.unlock();

2. Семафоры (Semaphore) Счетчик, ограничивающий количество потоков, одновременно входящих в критическую секцию. В отличие от мьютекса, семафор может разрешать доступ нескольким потокам.

3. Условные переменные (Condition Variable) Позволяют потокам ожидать выполнения определенного условия, связанного с общими данными. Часто используются в паре с мьютексом.

std::condition_variable cv;
std::mutex mtx;
bool data_ready = false;

// Поток-потребитель
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return data_ready; });

4. Атомарные операции и типы Гарантируют неделимость операций чтения-модификации-записи без использования блокировок.

std::atomic<int> counter(0);
counter.fetch_add(1, std::memory_order_relaxed); // Атомарное инкрементирование

5. Спинлоки (Spinlock) Примитив, при котором поток в цикле проверяет доступность блокировки, вместо того чтобы отдавать управление планировщику ОС. Эффективен при очень коротких критических секциях.

Выбор примитива зависит от контекста:

  • Мьютекс — для защиты доступа к общему ресурсу.
  • Условная переменная — для координации работы потоков по событиям.
  • Атомарные операции — для простых операций над счетчиками или флагами, где важна производительность.
  • Семафор — для ограничения доступа к пулу ресурсов (например, соединений с БД).

Видео-ответы