C++11 标准中定义了另外一个与 Mutex RAII 相关类 unique_lock
,该类与 lock_guard
类相似,也很方便线程对互斥量上锁,但它提供了更好的上锁和解锁控制。
unique_lock
对象以独占所有权的方式( unique owership)管理 mutex 对象的上锁和解锁操作,所谓独占所有权,就是没有其他的 unique_lock
对象同时拥有某个 mutex 对象的所有权。
在构造(或移动(move)赋值)时,unique_lock
对象需要传递一个 Mutex 对象作为它的参数,新创建的 unique_lock
对象负责传入的 Mutex 对象的上锁和解锁操作。
std::unique_lock
的构造函数的数目相对来说比 std::lock_guard
多,其中一方面也是因为 std::unique_lock
更加灵活,从而在构造 std::unique_lock
对象时可以接受额外的参数。总地来说,std::unique_lock
构造函数如下:
default (1) |
|
新创建的 unique_lock 对象不管理任何 Mutex 对象。 |
---|---|---|
locking (2) |
|
新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.lock() 对 Mutex 对象进行上锁,如果此时另外某个 unique_lock 对象已经管理了该 Mutex 对象 m,则当前线程将会被阻塞。 |
try-locking (3) |
|
新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.try_lock() 对 Mutex 对象进行上锁,但如果上锁不成功,并不会阻塞当前线程。 |
deferred (4) |
|
新创建的 unique_lock 对象管理 Mutex 对象 m,但是在初始化的时候并不锁住 Mutex 对象。 m 应该是一个没有当前线程锁住的 Mutex 对象。 |
adopting (5) |
|
新创建的 unique_lock 对象管理 Mutex 对象 m, m 应该是一个已经被当前线程锁住的 Mutex 对象。(并且当前新创建的 unique_lock 对象拥有对锁(Lock)的所有权) |
locking for (6) |
|
新创建的 unique_lock 对象管理 Mutex 对象 m,并试图通过调用 m.try_lock_for(rel_time) 来锁住 Mutex 对象一段时间(rel_time)。 |
locking until (7) |
|
新创建的 unique_lock 对象管理 Mutex 对象m,并试图通过调用 m.try_lock_until(abs_time) 来在某个时间点(abs_time)之前锁住 Mutex 对象。 |
copy [deleted] (8) |
|
unique_lock 对象不能被拷贝构造。 |
move (9) |
|
新创建的 unique_lock 对象获得了由 x 所管理的 Mutex 对象的所有权(包括当前 Mutex 的状态)。调用 move 构造之后, x 对象如同通过默认构造函数所创建的,就不再管理任何 Mutex 对象了。 |
综上所述,由 (2) 和 (5) 创建的 unique_lock
对象通常拥有 Mutex 对象的锁。而通过 (1) 和 (4) 创建的则不会拥有锁。通过 (3),(6) 和 (7) 创建的 unique_lock
对象,则在 lock 成功时获得锁。
std::unique_lock
支持移动赋值(move assignment),但是普通的赋值被禁用了。
move (1) |
|
移动赋值(move assignment)之后,由 x 所管理的 Mutex 对象及其状态将会被新的 std::unique_lock 对象取代。 |
---|---|---|
copy [deleted] (2) |
|
如果被赋值的对象之前已经获得了它所管理的 Mutex 对象的锁,则在移动赋值(move assignment)之前会调用 unlock 函数释放它所占有的锁。 |
由于 std::unique_lock
比 std::lock_guard
操作灵活,因此它提供了更多成员函数。具体分类如下:
- 上锁/解锁操作:
lock
,try_lock
,try_lock_for
,try_lock_until
和unlock
- 修改操作:移动赋值(move assignment)(前面已经介绍过了),交换(swap)(与另一个 std::unique_lock 对象交换它们所管理的 Mutex 对象的所有权),释放(release)(返回指向它所管理的 Mutex 对象的指针,并释放所有权)
- 获取属性操作:
owns_lock
(返回当前std::unique_lock
对象是否获得了锁)、operator bool()
(与owns_lock
功能相同,返回当前std::unique_lock
对象是否获得了锁)、mutex(返回当前 std::unique_lock 对象所管理的 Mutex 对象的指针)。
std::unique_lock::lock
- 上锁操作,调用它所管理的 Mutex 对象的 lock 函数。如果在调用 Mutex 对象的 lock 函数时该 Mutex 对象已被另一线程锁住,则当前线程会被阻塞,直到它获得了锁。
- 该函数返回时,当前的 unique_lock 对象便拥有了它所管理的 Mutex 对象的锁。如果上锁操作失败,则抛出 system_error 异常。
std::mutex mtx; // mutex for critical section
void print_thread_id (int id) {
std::unique_lock<std::mutex> lck (mtx,std::defer_lock);
// critical section (exclusive access to std::cout signaled by locking lck):
lck.lock();
std::cout << "thread #" << id << '\n';
lck.unlock();
}
std::unique_lock::try_lock
- 上锁操作,调用它所管理的 Mutex 对象的
try_lock
函数,如果上锁成功,则返回 true,否则返回 false。即便上锁失败也不会阻塞。
std::mutex mtx; // mutex for critical section
void print_star () {
std::unique_lock<std::mutex> lck(mtx,std::defer_lock);
// print '*' if successfully locked, 'x' otherwise:
if (lck.try_lock())
std::cout << '*';
else
std::cout << 'x';
}
std::unique_lock::try_lock_for/try_lock_until(仅用于timed系列的mutex)
- 上锁操作,调用它所管理的 Mutex 对象的 try_lock_for 函数,函数最多会等待指定的时间,如果获得锁,则返回 true,否则返回 false。
std::timed_mutex mtx;
// 等待指定时长
template <class Rep, class Period>
try_lock_for(const chrono::duration<Rep, Period>& rel_time);
// 等待到指定时间
template <class Clock, class Duration>
try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
std::unique_lock::unlock
解锁操作,调用它所管理的 Mutex 对象的 unlock 函数。
std::unique_lock::release
返回指向它所管理的 Mutex 对象的指针,并释放所有权。
std::unique_lock::owns_lock
返回当前 std::unique_lock 对象是否获得了锁。
std::unique_lock::mutex
返回当前 std::unique_lock 对象所管理的 Mutex 对象的指针。
标签:std,对象,lock,try,Mutex,unique From: https://www.cnblogs.com/love-9/p/18093346