std::unique_lock

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() noexcept;
新创建的 unique_lock 对象不管理任何 Mutex 对象。
locking (2)
explicit unique_lock(mutex_type& m);
新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.lock() 对 Mutex 对象进行上锁,如果此时另外某个 unique_lock 对象已经管理了该 Mutex 对象 m,则当前线程将会被阻塞。
try-locking (3)
unique_lock(mutex_type& m, try_to_lock_t tag);
新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.try_lock() 对 Mutex 对象进行上锁,但如果上锁不成功,并不会阻塞当前线程。
deferred (4)
unique_lock(mutex_type& m, defer_lock_t tag) noexcept;
新创建的 unique_lock 对象管理 Mutex 对象 m,但是在初始化的时候并不锁住 Mutex 对象。 m 应该是一个没有当前线程锁住的 Mutex 对象。
adopting (5)
unique_lock(mutex_type& m, adopt_lock_t tag);
新创建的 unique_lock 对象管理 Mutex 对象 m, m 应该是一个已经被当前线程锁住的 Mutex 对象。(并且当前新创建的 unique_lock 对象拥有对锁(Lock)的所有权)
locking for (6)
template <class Rep, class Period>
unique_lock(mutex_type& m, const chrono::duration<Rep,Period>& rel_time);
新创建的 unique_lock 对象管理 Mutex 对象 m,并试图通过调用 m.try_lock_for(rel_time) 来锁住 Mutex 对象一段时间(rel_time)。
locking until (7)
template <class Clock, class Duration>
unique_lock(mutex_type& m, const chrono::time_point<Clock,Duration>& abs_time);
新创建的 unique_lock 对象管理 Mutex 对象m,并试图通过调用 m.try_lock_until(abs_time) 来在某个时间点(abs_time)之前锁住 Mutex 对象。
copy [deleted] (8)
unique_lock(const unique_lock&) = delete;
unique_lock 对象不能被拷贝构造。
move (9)
unique_lock(unique_lock&& x);
新创建的 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)
unique_lock& operator= (unique_lock&& x) noexcept;
移动赋值(move assignment)之后,由 x 所管理的 Mutex 对象及其状态将会被新的 std::unique_lock 对象取代。
copy [deleted] (2)
unique_lock& operator= (const unique_lock&) = delete;
如果被赋值的对象之前已经获得了它所管理的 Mutex 对象的锁,则在移动赋值(move assignment)之前会调用 unlock 函数释放它所占有的锁。

由于 std::unique_lockstd::lock_guard 操作灵活,因此它提供了更多成员函数。具体分类如下:

  1. 上锁/解锁操作:locktry_locktry_lock_fortry_lock_until  unlock
  2. 修改操作:移动赋值(move assignment)(前面已经介绍过了),交换(swap)(与另一个 std::unique_lock 对象交换它们所管理的 Mutex 对象的所有权),释放(release)(返回指向它所管理的 Mutex 对象的指针,并释放所有权)
  3. 获取属性操作: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 对象的指针。

posted @   小熊酱  阅读(1301)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示