<mutex>
The <mutex>
header, introduced in C++11, provides synchronization primitives for multi-threaded programming. It offers various types of mutexes and lock classes to help manage concurrent access to shared resources, preventing data races and ensuring thread safety.
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
std::mutex mtx;
int shared_value = 0;
void increment(int id) {
for (int i = 0; i < 1000; ++i) {
mtx.lock();
++shared_value;
mtx.unlock();
}
std::cout << "Thread " << id << " finished.\n";
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i) {
threads.emplace_back(increment, i);
}
for (auto& t : threads) {
t.join();
}
std::cout << "Final value: " << shared_value << std::endl;
return 0;
}
std::mutex
to protect a shared resource#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
std::mutex mtx;
int shared_value = 0;
void increment(int id) {
for (int i = 0; i < 1000; ++i) {
std::lock_guard<std::mutex> lock(mtx);
++shared_value;
}
std::cout << "Thread " << id << " finished.\n";
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i) {
threads.emplace_back(increment, i);
}
for (auto& t : threads) {
t.join();
}
std::cout << "Final value: " << shared_value << std::endl;
return 0;
}
std::lock_guard
for automatic locking and unlocking of the mutex#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
std::mutex mtx;
int shared_resource = 0;
void worker(int id) {
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
// Simulate some work before locking
std::this_thread::sleep_for(std::chrono::milliseconds(id * 100));
lock.lock();
shared_resource += id;
std::cout << "Thread " << id << " added " << id << ". New value: " << shared_resource << std::endl;
lock.unlock();
// Simulate more work after unlocking
std::this_thread::sleep_for(std::chrono::milliseconds(100));
lock.lock();
shared_resource *= 2;
std::cout << "Thread " << id << " doubled. New value: " << shared_resource << std::endl;
}
int main() {
std::vector<std::thread> threads;
for (int i = 1; i <= 5; ++i) {
threads.emplace_back(worker, i);
}
for (auto& t : threads) {
t.join();
}
return 0;
}
std::unique_lock
with deferred locking#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
std::timed_mutex resource_mutex;
void worker(int id) {
for (int i = 0; i < 3; ++i) {
if (resource_mutex.try_lock_for(std::chrono::milliseconds(200))) {
std::cout << "Thread " << id << " acquired lock.\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
resource_mutex.unlock();
} else {
std::cout << "Thread " << id << " couldn't acquire lock.\n";
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 4; ++i) {
threads.emplace_back(worker, i);
}
for (auto& t : threads) {
t.join();
}
return 0;
}
std::timed_mutex
to attempt locking with a timeouttry_lock_for()
method to attempt acquiring the lock for a specified durationstd::recursive_mutex
when a thread needs to acquire the same mutex multiple timesstd::shared_mutex
(C++17) allows multiple readers or a single writer, useful for read-heavy scenariosstd::atomic
for simple shared variablesThe <mutex>
header in C++ provides essential tools for synchronization in multi-threaded programs. It offers various mutex types and lock classes to help manage concurrent access to shared resources safely and efficiently.
Key points to remember:
1. Use std::mutex
for basic mutual exclusion
2. Prefer RAII-style locks like std::lock_guard
and std::unique_lock
for exception safety
3. std::unique_lock
offers more flexibility with deferred and timed locking
4. std::timed_mutex
allows for timed lock attempts
5. Always be mindful of potential deadlocks and performance implications when using mutexes
By effectively using the synchronization primitives provided by <mutex>
, C++ developers can write thread-safe code, manage shared resources, and build robust multi-threaded applications while minimizing the risks of data races and deadlocks.