C++ Standard Library<mutex>
In multithreaded programming, ensuring data consistency and thread safety is crucial.
The C++ standard library provides a rich set of synchronization primitives used to control access to shared resources.
In the C++ standard library,<mutex>The header file provides a set of tools for implementing synchronization and mutual exclusion between threads in multithreaded programs.
<mutex>The header file was introduced in C++11 and contains classes and functions for mutex locks. A mutex lock is a synchronization mechanism used to prevent multiple threads from accessing shared resources at the same time.
A mutex is a synchronization primitive used to control access to shared resources. When a thread needs to access a shared resource, it attempts to lock the mutex. If the mutex has already been locked by another thread, the requesting thread will be blocked until the mutex is released.
Basic Syntax
In C++,<mutex>The header file provides the following main classes:
std::mutex: Basic mutex.std::recursive_mutex: Recursive mutex lock, allowing the same thread to lock multiple times.std::timed_mutex: Mutex with timeout functionality.std::recursive_timed_mutex: Recursive mutex with timeout functionality.
Example
1. Usagestd::mutex
The following is a simple example showing how to use in C++std::mutexto synchronize access to shared resources.
Example
#include <thread>
#include <mutex>
std::mutex mtx; // Global mutex lock
int shared_resource = 0;
void increment() {
for (int i = 0; i < 10000; ++i) {
mtx.lock(); // Lock the mutex
++shared_resource;
mtx.unlock(); // Unlock the mutex
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Final value of shared_resource: " << shared_resource << std::endl;
return 0;
}
Output result:
Final value of shared_resource: 20000
2. Usagestd::recursive_mutex
A recursive mutex lock allows the same thread to lock the same mutex multiple times. The following is an example usingstd::recursive_mutexExample.
Example
#include <thread>
#include <mutex>
std::recursive_mutex rmtx; // Create a recursive mutex object
int shared_resource = 0; // Shared resource
// Recursive function
void recursive_increment(int count) {
if (count <= 0) return;
std::lock_guard<std::recursive_mutex> lock(rmtx); // Lock to ensure thread safety
++shared_resource;
std::cout << "Incremented shared_resource to " << shared_resource << " (count = " << count << ")" << std::endl;
// Recursive call
recursive_increment(count - 1);
}
int main() {
std::thread t1(recursive_increment, 3); // Thread t1 executes recursive_increment(3)
std::thread t2(recursive_increment, 3); // Thread t2 executes recursive_increment(3)
t1.join(); // Wait for thread t1 to finish
t2.join(); // Wait for thread t2 to finish
std::cout << "Final value of shared_resource: " << shared_resource << std::endl;
return 0;
}
Output result:
Incremented shared_resource to 1 (count = 3) Incremented shared_resource to 2 (count = 2) Incremented shared_resource to 3 (count = 1) Incremented shared_resource to 4 (count = 0) Incremented shared_resource to 5 (count = 3) Incremented shared_resource to 6 (count = 2) Incremented shared_resource to 7 (count = 1) Incremented shared_resource to 8 (count = 0) Final value of shared_resource: 8
Code Analysis:
Create
std::recursive_mutexObject:std::recursive_mutex rmtx;Is a recursive mutex that allows the same thread to acquire the lock multiple times.Shared resource:
int shared_resource = 0;is a resource accessed by multiple threads concurrently.Recursive function
recursive_increment:- Usage
std::lock_guard<std::recursive_mutex>PairrmtxLock. Since a recursive mutex is used, the same thread can acquire the lock multiple times. - Through
++shared_resourceIncreases the value of the shared resource. - The function recursively calls itself, demonstrating how a recursive function works safely when locked multiple times.
- Usage
Creating and Running Threads:
std::thread t1(recursive_increment, 3);andstd::thread t2(recursive_increment, 3);Two threads are created separately, and both will executerecursive_increment(3)。t1.join()andt2.join()Waits for two threads to complete execution.
Notes
- Ensure that after each mutex lock is acquired, an unlock operation is performed to avoid deadlock.
- Usage
std::lock_guardorstd::unique_lockCan automatically manage the locking and unlocking of mutex locks, reducing the possibility of errors. - Avoid calling functions that may throw exceptions while holding a mutex lock, because this may lead to deadlock.
<mutex>Is a very important header file in the C++ standard library, providing basic synchronization mechanisms for multithreaded programming. By using mutex locks, we can ensure that access to shared resources is safe, thereby avoiding data races and inconsistency issues.
More information
1. std::mutex
Provide a basic mutex to ensure that only one thread can access shared resources at the same time.
Example
std::mutex mtx;
void thread_function() {
std::lock_guard<std::mutex> lock(mtx);
// Access shared resource
}
2. std::recursive_mutex
Allow the same thread to acquire the lock multiple times without causing deadlock, which is especially useful for recursive functions.
Example
std::recursive_mutex rmtx;
void recursive_function(int count) {
if (count <= 0) return;
std::lock_guard<std::recursive_mutex> lock(rmtx);
// Recursive call
recursive_function(count - 1);
}
3. std::timed_mutex
Provides a timed mutex that can set a timeout when attempting to acquire the lock.
Example
#include <chrono>
std::timed_mutex tm;
void try_lock_for_example() {
if (tm.try_lock_for(std::chrono::seconds(1))) {
// Successfully acquired the lock
tm.unlock();
} else {
// Failed to acquire the lock
}
}
4. std::recursive_timed_mutex
Inherited from std::timed_mutex, allowing the same thread to acquire the lock multiple times while also supporting timed functionality.
Example
#include <chrono>
std::recursive_timed_mutex rtm;
void recursive_timed_function(int count) {
if (count <= 0) return;
if (rtm.try_lock_for(std::chrono::seconds(1))) {
// Successfully acquired the lock
recursive_timed_function(count - 1);
rtm.unlock();
} else {
// Failed to acquire the lock
}
}
5. std::lock_guard
A wrapper that automatically manages std::mutex locks, using the RAII style to ensure that the lock is automatically released when the scope ends.
Example
std::mutex mtx;
void function() {
std::lock_guard<std::mutex> lock(mtx);
// Access shared resource
}
6. std::unique_lock
Provide more flexible lock management than std::lock_guard, allowing manual release and re-acquisition of locks, and also supporting timed locking.
Example
#include <chrono>
std::mutex mtx;
void function() {
std::unique_lock<std::mutex> lock(mtx);
// Access shared resource
// Can manually release the lock
lock.unlock();
// Can reacquire the lock
lock.lock();
// Can perform timed locking
if (lock.try_lock_for(std::chrono::seconds(1))) {
// Successfully acquired the lock
}
}
7. std::adopt_lock_t
A flag type used to specify that std::unique_lock adopts an existing lock.
Example
std::unique_lock<std::mutex> lock(mtx, std::adopt_lock);
8. std::defer_lock_t
Function: A flag type used for deferred locking, and no lock is acquired during initialization.
Example
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
// Can call lock.lock() at some later time
9. std::try_to_lock_t
Flag type, used to attempt locking without blocking.
Example
std::unique_lock<std::mutex> lock1(mtx1, std::try_to_lock);
std::unique_lock<std::mutex> lock2(mtx2, std::try_to_lock);
if (lock1 && lock2) {
// Successfully acquired both locks
}