std::unique_lock
-
The same basic features as
std::lock_guard- Mutex data member
- Constructor locks the mutex
- Destructor unlocks it
-
It also has an
unlock()member function- We can call this after the critical section
- Avoids blocking other threads while we execute non-critical code
-
If we do not call
unlock(), the destructor will unlock the mutex- The lock is always released
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
using namespace std::literals;
std::mutex print_mutex;
void task(std::string str) {
for (int i = 0; i < 5; ++i) {
// Creat an std::unique_lock object
// This calls print_mutex.lock();
std::unique_lock<std::mutex> uniq_lck(print_mutex);
// Critical section begin
std::cout << str[0] << str[1] << str[2] << std::endl;
// Critical section end
uniq_lck.unlock();
std::this_thread::sleep_for(50ms);
} // Calls ~std::unique_lock
}
int main() {
std::thread thr1(task, "abc");
std::thread thr2(task, "def");
std::thread thr3(task, "wyz");
thr1.join();
thr2.join();
thr3.join();
}
std::unique_lock Constructor Options
-
The default
- Call the mutex's
lock()member function
- Call the mutex's
-
Try to get the lock
- Do not wait if unsuccessful
- (Timed mutex) Wait with a time-out if unsuccessful
-
Do not lock the mutex
- It will be locked later
- Or the mutex is already locked
std::unique_lock Constructor Optional Second Argument
-
std::try_to_lock- Calls the mutex's
try_lock()member function - The
owns_lock()member function checks if the mutex is locked
- Calls the mutex's
-
std::defer_lock- Does not lock the mutex
- Can lock it later by calling the
lock()member function - Or by passing the
std::unique_lockobject tostd::lock()
-
std::adopt_lock- Takes a mutex that is already locked
- Avoids locking the mutex twice
std::unique_lock and Move Semantics
-
A
std::unique_lockobject cannot be copied -
It can be moved
- The lock is transferred to another
std::unique_lockobject - Can only be done within the same thread
- The lock is transferred to another
-
We can write a function that creates a lock object and returns it
- The function could lock different types of mutex, depending on its arguments
- Factory design pattern
std::unique_lock vs std::lock_guard
-
std::unique_lockis much more flexible, but- Requires slightly more storage
- Is slightly slower
-
Recommendations:
- Use
lock_guardto lock a mutex for an entire scope - Use
unique_lockif you need to unlock within the scope - Use
unique_lockif you need the extra features
- Use