Синхронизация потоков
Как синхронизировать передачи информации между потоками?
Для синхронизации передачи информации между потоками в C++ используются различные механизмы синхронизации:
-
Мьютексы (
std::mutex):- Предотвращают одновременный доступ к критическим участкам кода.
#include <mutex> std::mutex mtx; void threadFunc() { std::lock_guard<std::mutex> lock(mtx); // Доступ к общим данным } -
Условные переменные (
std::condition_variable):- Обеспечивают ожидание одного потока до наступления определённого условия, установленного другим потоком.
#include <condition_variable> std::mutex mtx; std::condition_variable cv; bool ready = false; void producer() { std::unique_lock<std::mutex> lock(mtx); // Подготовка данных ready = true; cv.notify_one(); // Уведомление потребителя } void consumer() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return ready; }); // Ожидание готовности // Обработка данных } -
Атомарные операции (
std::atomic):- Обеспечивают атомарные операции над поддерживаемыми типами. Реализация может использовать внутренние блокировки; несколько операций не становятся одной неделимой последовательностью.
#include <atomic> std::atomic<int> counter(0); void increment() { counter++; } -
Блокировки с отсчётом (
std::latchиstd::barrierв C++20):- Координируют потоки, позволяя им ожидать друг друга в определённых точках выполнения.
#include <latch> std::latch latch(1); void threadFunc1() { // Работа потока latch.count_down(); // Уменьшение счётчика } void threadFunc2() { latch.wait(); // Ожидание обнуления счётчика // Работа потока }
Какая разница между мьютекс и семафором?
Оба механизма служат для синхронизации, но используются в разных сценариях в зависимости от потребностей в ограничении доступа к ресурсам.
Мьютекс (Mutex):
-
Назначение: Используется для обеспечения взаимного исключения при доступе к общим ресурсам.
-
Количество потоков: Позволяет доступ только одному потоку в каждый момент времени.
-
Использование: Легковесен и используется для защиты критических участков кода.
-
Поведение: Поток, захвативший мьютекс, должен освободить его.
std::mutex mtx; mtx.lock(); // Критическая секция mtx.unlock();
Семафор (Semaphore):
-
Назначение: Управляет доступом к ресурсу с ограниченным числом экземпляров.
-
Количество потоков: Позволяет доступ нескольким потокам одновременно до определённого лимита.
-
Использование: Может использоваться для более сложных сценариев синхронизации, таких как контроль доступа к пулу ресурсов.
-
Поведение: Поддерживает счётчик, который увеличивается при освобождении и уменьшается при захвате.
std::counting_semaphore<3> sem(3); sem.acquire(); // Доступ к ресурсу sem.release();
Основные отличия:
-
Мьютекс: Гарантирует доступ только одному потоку.
-
Семафор: Может разрешить доступ нескольким потокам до заданного лимита.