unique_lock or lock_guard: Which Is Better? (original) (raw)
Last Updated : 8 May, 2025
In C++, to manage access to shared resources, the STL (standard template library) of C++, provides synchronization mechanisms such as **lock_guard and **unique_lock. Both are useful for managing mutex but have different features and use cases.
In this article, we will discuss the advantages, disadvantages, differences, and use cases of both unique_lock and lock_guard in C++
unique_lock
**unique_lock offers more flexibility than **lock_guard. It provides features like manual locking and unlocking, deferred locking, and ownership transfer. Unlike lock_guard, which automatically locks and unlocks the mutex, unique_lock requires explicit calls to lock and unlock. The following is the syntax to use unique_lock in C++:
**Syntax
C++ `
shared_lock Name(myMutex, lockingBehavior);
`
where,
- **name: Name assign to **shared_lock object
- **myMutex: It is a placeholder for the actual type of the mutex.
- **lockingBehavior: This is the optional parameter, which determines how the mutex is locked and managed.
Example
The following program illustrates the use of unique_lock in C++:
C++ `
// C++ Program using std::unique_lock #include #include #include using namespace std;
// Global mutex to protect shared_data mutex mtx;
// Shared data variable int shared_data = 0;
// Function to increment shared_data void increment_data() { // Create a unique_lock object, but defer locking the mutex unique_lock lock(mtx, defer_lock);
// Explicitly acquire the lock
lock.lock();
// Critical section: safely modify shared_data
shared_data += 2;
// Manually release the lock
lock.unlock(); }
int main() { // Create two threads that run the increment_data function thread t1(increment_data); thread t2(increment_data);
// Wait for both threads to finish
t1.join();
t2.join();
// Output the value of shared_data
cout << "Value of shared variable: " << shared_data;
return 0;}
`
**Output
Value of shared variable: 4
**Time Complexity: O(1)
**Auxiliary Space: O(1)
**Key Features
Following are some key features of unique_lock:
- **Flexibility: Can lock and unlock multiple times within its scope.
- **Deferred Locking: This can be constructed without locking the mutex immediately.
- **Timed Locking: Supports times and try-locking operations.
- **Ownership Transfer: It allows transferring mutex ownership to another unique_lock.
**Usage
Following are the use cases when you should consider using unique_lock:
- You need more control over the locking mechanism including ability to lock and unlock manually.
- You need to defer locking or conditionally lock a mutex.
- You require timed locking to prevent blocking indefinitely.
- You need to transfer lock ownership between different scopes or threads.
lock_guard
In C++, **lock_guard is a simple class that is used to manage the locking and unlocking of a mutex. Its main purpose is to automatically lock a mutex when it is created and automatically unlock it when the lock_guard object goes out of scope. Following is the syntax to use lock_guard in C++:
Syntax
C++ `
lock_guard name(myMutex);
`
where,
- **name: Name assign to **shared_lock object
- **myMutex: It is a placeholder for the actual type of the mutex.
Example
The following program illustrates the use of lock_guard in C++:
C++ `
// C++ Program using std::lock_guard #include #include #include using namespace std;
// Global mutex to protect shared_data mutex mtx;
// Shared data variable int shared_data = 0;
// Function to increment shared_data void increment_data() { // Create a lock_guard object which locks the mutex lock_guard lock(mtx);
// Critical section: safely modify shared_data
shared_data+=2;
// Lock is automatically released when 'lock' goes out of scope}
int main() { // Create two threads that run the increment_data function thread t1(increment_data); thread t2(increment_data);
// Wait for both threads to finish
t1.join();
t2.join();
// Output the value of shared_data
cout << "Value of shared variable: " << shared_data;
return 0;}
`
**Output
Value of shared variable: 4
**Time Complexity: O(1)
**Auxiliary Space: O(1)
**Key Features
Following are some key features of unique_lock:
- **Simplicity: lock_guard is very simple to use with minimal overhead.
- **RAII(Resource Acquisition Is Initialization) ****:** Ensures that mutex is released when the lock_guard goes out of scope.
- **No Unlocking: Does not support manual unlocking before the end of its scope.
**Usage
Following are the use cases when you should consider using lock_guard:
- It is used when you need simple lock that automatically unlocks when the scope ends.
- The locking operation is straightforward and does not require unlocking before scope ends.
- You prioritize minimal overhead and simplicity.
Difference between lock_guard and unique_lock
Following are some key differences between lock_guard and unique_lock in C++:
| Features | lock_guard | unique_lock |
|---|---|---|
| Complexity | Simple and minimal overhead. | It is more complex and have additional overhead due to extra features. |
| Locking behavior | Locks mutex upon construction and destruction. | Can lock and unlock multiple times within its scope and supports deferred locking. |
| Flexibility | No manual control over locking and unlocking. | There is manual control over locking and unlocking. |
| Deferred Locking | Not supported. | Supported. |
| Timed Locking | Not supported. | Supported. |
| Ownership Transfer | Not supported. | Supported. |
| Ideal Usage | Used where simple and single-scope locking is needed. | Used in complex scenarios needing lock control and flexibility. |
| Exception Safety | Guarantees unlock on destruction | It guarantees unlock on destruction more control may increase error risk if misused |
| Overhead | Minimal | Slightly higher due to additional features. |
| Example Use Case | Simple critical sections. | Conditional locking, timed locking and transferring lock ownership. |
Conclusion
In conclusion, both unique_lock and lock_guard are powerful tools provided by the C++ standard library for managing mutexes and ensuring thread safety. lock_guard offers a simple, efficient way to lock and unlock a mutex within a scope, making it ideal for straightforward locking needs.Choosing between them depends on the specific requirements of your code.