3.std::unique_lock
4.std:unique_lock方法介绍
通常作为参数传入给 unique_lock 或 lock_guard 的构造函数。后面我们会详细介绍以上三种 Tag 类型在配合 lock_gurad 与 unique_lock 使用时的区别。
2.std::lock_guard
std::lock_gurad 是 C++11 中定义的模板类。定义如下:
template
lock_guard 对象通常用于管理某个锁(Lock)对象,因此与 Mutex RAII 相关,方便线程对互斥量上锁,即在某个 lock_guard 对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而 lock_guard 的生命周期结束之后,它所管理的锁对象会被解锁(注:类似 shared_ptr 等智能指针管理动态分配的内存资源 )。
locking 初始化
lock_guard 对象管理 Mutex 对象 m,并在构造时对 m 进行上锁(调用 m.lock())。
std::lock_guard lck(mtx);
mtx.lock();
std::lock_guard lck(mtx, std::adopt_lock);
3.std::unique_lock 介绍
但是 lock_guard 最大的缺点也是简单,没有给程序员提供足够的灵活度,因此,C++11 标准中定义了另外一个与 Mutex RAII 相关类 unique_lock,该类与 lock_guard 类相似,也很方便线程对互斥量上锁,但它提供了更好的上锁和解锁控制。
顾名思义,unique_lock 对象以独占所有权的方式( unique owership)管理 mutex 对象的上锁和解锁操作,所谓独占所有权,就是没有其他的 unique_lock 对象同时拥有某个 mutex 对象的所有权。
在构造(或移动(move)赋值)时,unique_lock 对象需要传递一个 Mutex 对象作为它的参数,新创建的 unique_lock 对象负责传入的 Mutex 对象的上锁和解锁操作。
下面我们来分别介绍以上各个构造函数:
(1) 默认构造函数
新创建的 unique_lock 对象不管理任何 Mutex 对象。
(2) locking 初始化
新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.lock() 对 Mutex 对象进行上锁,如果此时另外某个 unique_lock 对象已经管理了该 Mutex 对象 m,则当前线程将会被阻塞。
unique_lock uniqueloc1;
uniqueloc1 = unique_lock(mtx1);
新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.try_lock() 对 Mutex 对象进行上锁,但如果上锁不成功,并不会阻塞当前线程。
lck1 = unique_lock(mtx1, try_to_lock);
unique_lock lck1, lck2;
lck1 = unique_lock(mtx1, defer_lock);
lck2 = unique_lock(mtx2, defer_lock);
lock(lck1, lck2);
cout << this_thread::get_id() << endl;
mutex mtx1,mtx2;
void test()
{
lock(mtx1, mtx2);
unique_lock lck1, lck2;
lck1 = unique_lock(mtx1, adopt_lock);
lck2 = unique_lock(mtx2, adopt_lock);
cout << this_thread::get_id() << endl;
}
新创建的 unique_lock 对象获得了由 x 所管理的 Mutex 对象的所有权(包括当前 Mutex 的状态)。调用 move 构造之后, x 对象如同通过默认构造函数所创建的,就不再管理任何 Mutex 对象了。
4.std:unique_lock方法介绍
1.std::unique_lock::lock
上锁操作,调用它所管理的 Mutex 对象的 lock 函数。如果在调用 Mutex 对象的 lock 函数时该 Mutex 对象已被另一线程锁住,则当前线程会被阻塞,直到它获得了锁。
2.std::unique_lock::unlock
解锁操作,调用它所管理的 Mutex 对象的 unlock 函数。
3.std::unique_lock::try_lock
上锁操作,调用它所管理的 Mutex 对象的 try_lock 函数,如果上锁成功,则返回 true,否则返回 false。
lck.try_lock()
try_lock_for(std::chrono::milliseconds(200))
lck.try_lock_until(chrono::steady_clock::now()+chrono::seconds(3))
mutex* p_mtx = lck.release()
p_mtx->unlock();
std::unique_lock lck(mtx,std::try_to_lock);
// print '*' if successfully locked, 'x' otherwise:
if (lck.owns_lock())
std::unique_lock lck(mtx,std::try_to_lock);
// print '*' if successfully locked, 'x' otherwise:
if (lck)
std::unique_lock lck (mtx);
std::cout << "thread #" << id << " locked mutex " << lck.mutex()->id() << '\n';