std::adopt_lock_t
struct adopt_lock_t {};
该类是一个空类,用于定义adopt_lock
常量对象,adopt_lock
可传递给unique_lock
和lock_guard
的构造函数,使得它们在构造对象时不会对mutex
对象上锁,而是假定mutex
对象已经被当前线程上锁,并标记自身状态为已拥有锁。
adopt_lock
常量位于std
命名空间中:
constexpr adopt_lock_t adopt_lock {};
std::defer_lock_t
struct defer_lock_t {};
defer_lock_t
也是一个空类,用于定义常量defer_lock
。可以将它传递给unique_lock
的构造函数,使其在构造对象时不会自动地锁住mutex
对象,并将unique_lock
初始化为不拥有锁。
defer_lock
常量位于std
命名空间中:
constexpr defer_lock_t defer_lock {};
std::try_to_lock_t
struct try_to_lock_t {};
try_to_lock_t
创建的常量对象try_to_lock
可传递给unique_lock
的构造函数,构造函数会调用try_lock
函数尝试锁住mutex
对象,若成功上锁,则标记unique_lock
对象的状态为拥有锁;否则,标记该对象的状态为没有拥有锁。
constexpr try_to_lock_t try_to_lock {};
std::lock_guard
template <class Mutex> class lock_guard;
lock_guard
类用于管理锁类型的对象,在构造函数中会上锁,直到调用析构函数时才会解锁。
lock_guard构造函数
explicit lock_guard (mutex_type& m);
lock_guard (mutex_type& m, adopt_lock_t tag);
lock_guard (const lock_guard&) = delete;
- 第一种构造函数会调用
m.lock()
函数锁住m
,需要显式调用该构造函数;若m
已经上锁,则会抛出异常 - 第二种构造函数不会上锁,而是认为当前线程已经对
m
上锁了,仅仅是领养m
。因此,线程必须对m
上锁。 lock_guard
对象不可拷贝和移动。
lock_guard析构函数
~lock_guard();
该析构函数会调用unlock
函数解锁,并销毁lock_guard
对象,但不会销毁mutex
对象。
#include <iostream>
#include <mutex>
std::mutex mt1, mt2;
int main(int argc, char** argv)
{
mt1.lock();//mt1上锁
{
std::lock_guard<std::mutex> lck_guard1(mt1, std::adopt_lock_t{});//lck_guard1不会对mt1上锁,而是adopt该锁,在此之前,mt1应该已上锁
}//lck_guard1会被销毁,调用析构函数会解锁mt1
{
std::lock_guard<std::mutex> lck_guard2(mt2, std::adopt_lock_t{});
}//lck_guard2会被销毁,并调用析构函数解锁mt2,由于mt2并没有上锁,因此会抛出system_error异常,提示“unlock of unowned mutex”
return 0;
}
std::unique_lock
template <class Mutex> class unique_lock;
unique_lock
有两个私有数据成员,指针和状态,指针指向管理的锁类型的对象,状态标记则标记unique_lock
对象是否拥有锁。
与lock_guard
一样,unique_lock
也用于管理锁类型的对象,但更加灵活,可以手动的上锁和解锁、释放锁(放弃对锁对象的管理权)和移交锁等操作。
构造函数
- 默认构造函数
unique_lock() noexcept;
默认构造函数,没有可管理的锁类型对象。
- locking initialization
explicit unique_lock (mutex_type& m);
管理锁类型对象m
,并调用m.lock()
对其进行上锁,若已处于上锁状态,则会阻塞当前线程。
- try-locking initialization
unique_lock (mutex_type& m, try_to_lock_t tag);
管理锁类型对象m
,并调用m.try_lock()
尝试上锁。
- deferred initialization
unique_lock (mutex_type& m, defer_lock_t tag) noexcept;
管理锁类型对象m
,但不会对其上锁。m
不该被构造线程锁住。
- adopting initialization
unique_lock (mutex_type& m, adopt_lock_t tag);
m
对象被构造线程锁住,unique_lock
对象获得锁的所有权。
- locking for duration
template <class Rep, class Period>
unique_lock (mutex_type& m, const chrono::duration<Rep,Period>& rel_time);
通过调用m.try_lock_for(rel_time)
函数,尝试在rel_time
时间内锁住m
。
- locking until time point
template <class Clock, class Duration>
unique_lock (mutex_type& m, const chrono::time_point<Clock,Duration>& abs_time);
通过调用m.try_lock_until(abs_time)
,尝试在abs_time
之前锁住m
。
- copy construction [deleted]
unique_lock (const unique_lock&) = delete;
拷贝构造函数不可用。
- move construction
unique_lock (unique_lock&& x);
移动构造函数,当前对象会获得由x
管理的锁对象,包括锁的状态。
析构函数
~unique_lock();
若对象现在拥有锁,先解锁,然后再销毁该对象。但不会销毁锁类型对象。
成员函数
unique_lock::owns_lock
若管理的锁类型对象被该对象锁住或adopted,并且在调用该函数时还未解锁或释放锁类型对象,则返回true
。其他情况返回false
。
该函数与unique_lock::operator bool
作用一样。
unique_lock::lock
void lock();
调用管理的锁类型对象的lock
函数进行上锁,若该锁类型对象已经被其他线程锁住,则当前线程阻塞,直到可以拥有锁时。
当函数返回时,unique_lock
对象就获得了锁。
unique_lock::try_lock
bool try_lock();
该函数会调用锁类型对象的try_lock
成员函数。若该对象没有管理锁类型对象或锁类型对象已经被上锁,则函数被抛出system_error
异常。
成功获得锁则返回true
,否则返回false
。
unique_lock::try_lock_for
template <class Rep, class Period>
bool try_lock_for (const chrono::duration<Rep,Period>& rel_time);
unique_lock::try_lock_until
template <class Clock, class Duration>
bool try_lock_until (const chrono::time_point<Clock,Duration>& abs_time);
unique_lock::unlock
void unlock();
若没有管理锁,或不拥有锁,则抛出异常;否则调用锁的unlock()
函数。
unique_lock::mutex
mutex_type* mutex() const noexcept;
返回管理的锁类型对象的指针。
unique_lock::operator=
移动赋值运算符:
unique_lock& operator= (unique_lock&& x) noexcept;
用x
管理的锁类型对象替换当前管理的锁类型对象,包括锁的状态。
若当前对象管理的锁类型对象已经上锁,则先解锁再替换。
拷贝赋值运算符:
unique_lock& operator= (const unique_lock&) = delete;
unique_lock::operator bool
explicit operator bool() const noexcept;
若管理的锁类型对象被当前对象上锁或adopted,则返回true
。
与owns_lock
函数功能一样。
unique_lock::release
mutex_type* release() noexcept;
释放对管理的锁类型对象的所有权,并返回锁类型对象的指针。
调用该函数后,当前对象便处于没有管理任何锁类型对象的状态(与使用默认构造函数构造的对象的状态一样)。
该函数不会对释放的锁类型对象进行上锁或解锁操作。
unique_lock::swap
void swap (unique_lock& x) noexcept;
交换当前对象与x
的内容,包括管理的锁类型对象和当前的拥有状态(当前对象对锁类型对象上锁了或adopted
,就是拥有该锁的状态,否则就是不拥有该锁)。
友元函数
std::swap
template <class Mutex>
void swap (unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
交换x
和y
。