Ответ
В стандартной библиотеке C++ (заголовки <mutex>, <atomic>, <condition_variable>, <shared_mutex>) есть набор примитивов, которые я применяю в зависимости от задачи:
-
std::mutexи RAII-обертки (std::lock_guard,std::unique_lock): Это мой основной инструмент для защиты критических секций. Я почти всегда использую их вместе, чтобы избежать ручного вызоваlock()/unlock().std::mutex dataMutex; std::vector<int> sharedData; void safePush(int value) { std::lock_guard<std::mutex> lock(dataMutex); sharedData.push_back(value); } // Мьютекс освобождается автоматически -
std::unique_lock: Использую, когда нужна более гибкая блокировка, например, для условных переменных или отложенного захвата.std::mutex mtx; std::condition_variable cv; bool dataReady = false; void consumer() { std::unique_lock<std::mutex> ul(mtx); cv.wait(ul, []{ return dataReady; }); // Автоматически отпускает и снова захватывает мьютекс // Обработка данных } -
std::atomic: Применяю для простых счетчиков, флагов или указателей, где нужна атомарность без полноценной блокировки. Это дает выигрыш в производительности для высоконагруженных участков.std::atomic<int> activeConnections{0}; void onNewConnection() { ++activeConnections; // Атомарная операция } -
std::condition_variable: Незаменим для реализации паттернов Producer-Consumer, когда потоку нужно ждать наступления какого-либо условия (например, появления задачи в очереди). -
std::shared_mutex(C++17): Использую в сценариях "много читателей, один писатель" (read-write lock). Например, для защиты кэша конфигурации, который часто читается, но редко обновляется.std::shared_mutex cacheMutex; ConfigCache globalCache; std::string getConfig(const std::string& key) { std::shared_lock lock(cacheMutex); // Множество потоков могут читать одновременно return globalCache.get(key); } void updateConfig(const std::string& key, const std::string& value) { std::unique_lock lock(cacheMutex); // Только один писатель globalCache.set(key, value); }
Я избегаю использования std::recursive_mutex, так как его необходимость часто указывает на проблему с дизайном, и предпочитаю std::scoped_lock для deadlock-free захвата нескольких мьютексов.