lock_guard
template<typename _Mutex>
class lock_guard
{
public:
typedef _Mutex mutex_type;
explicit lock_guard(mutex_type& __m) : _M_device(__m)
{ _M_device.lock(); }
~lock_guard()
{ _M_device.unlock(); }
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete;
private:
mutex_type& _M_device;
};
- 构造函数中自动获取锁,析构函数中自动释放锁;
- 将拷贝构造函数和赋值运算符重载函数delete掉了,也就是说lock_guard将 不能做为函数参数传递或者函数的返回值;
- 使用了智能指针的思想,出作用域自动释放锁。
unique_lock
template<typename _Mutex>
class unique_lock
{
public:
typedef _Mutex mutex_type;
unique_lock() noexcept
: _M_device(0), _M_owns(false){}
explicit unique_lock(mutex_type& __m)
: _M_device(std::__addressof(__m)), _M_owns(false)
{
lock();
_M_owns = true;
}
~unique_lock()
{
if (_M_owns)
unlock();
}
//同样删除了带左值的拷贝构造函数和赋值运算符重载函数
unique_lock(const unique_lock&) = delete;
unique_lock& operator=(const unique_lock&) = delete;
//但是添加了带右值的拷贝构造函数和赋值运算符重载函数
unique_lock(unique_lock&& __u) noexcept
: _M_device(__u._M_device), _M_owns(__u._M_owns)
{
__u._M_device = 0;
__u._M_owns = false;
}
unique_lock& operator=(unique_lock&& __u) noexcept
{
if(_M_owns)
unlock();
unique_lock(std::move(__u)).swap(*this);
__u._M_device = 0;
__u._M_owns = false;
return *this;
}
void lock()
{
if (!_M_device)
__throw_system_error(int(errc::operation_not_permitted));
else if (_M_owns)
__throw_system_error(int(errc::resource_deadlock_would_occur));
else
{
_M_device->lock();
_M_owns = true;
}
}
void unlock()
{
if (!_M_owns)
__throw_system_error(int(errc::operation_not_permitted));
else if (_M_device)
{
_M_device->unlock();
_M_owns = false;
}
}
private:
mutex_type* _M_device;
bool _M_owns;
};
- 同样也是构造函数中获取锁,析构函数中释放锁;
- 同样删除了带左值的拷贝构造函数和赋值运算符重载函数
- 但是新增了带右值引用参数的拷贝构造函数和赋值运算符重载函数,这就使得unique_lock可以在函数传参或者参数返回中使用该锁。
- 提供了lock()和unlock()方法,才可以与条件变量condition_variable搭配使用。
#include <condition_variable>
#include <mutex>
std::condition_variable cdv_;
std::mutex mtx_;
std::unique_lock<std::mutex> lck(mtx_);
cdv_.wait(lck);
这里的wait()做了俩件事情:
- 把当前的线程置为睡眠状态,可能因为自身执行的条件不满足,如资源不足等;
- 调用lck的unlock()方法,将锁mtx_释放掉,这样才能让其他线程获取lock()到锁,占用cpu.
最后补充一个条件变量接口:
cdv_.notify_all();
cdv_.notify_one();
- 唤醒等待在cdv_上的所有的线程,然后再去获取该条件变量上的锁,获取到的继续执行
- 唤醒等待在cdv_上的一个线程,再去获取该条件变量上的锁,获取到继续执行