一、概要
unique_lock实现了lock_guard类似的功能,但unique_lock保证了只有一个unique_lock拥有mutex,同时提供了转移拥有权的接口。
二、代码示例
#pragma once
#include <mutex>
#include <thread>
#include <iostream>
using namespace std;
class UniqueLockTest
{
private:
mutex _mutex;
int count;
public:
void process()
{
for (int i = 0; i < 10000; i++)
{
unique_lock<mutex> lock1(_mutex);
//lock1.lock(); //unique_lock构造的时候已经lock了,再lock就死锁了
count++;
}
}
void doTest()
{
thread t1([this]() {
this->process(); });
thread t2([this]() {
this->process(); });
t1.join();
t2.join();
unique_lock<mutex> lock1(_mutex);
count++;
//unique_lock<mutex> lock2 = lock1; //编译过不了,赋值操作符被删除,避免mutex被两个对象引用
//unique_lock<mutex> lock2(lock1); //编译过不了,删除了拷贝构造函数
unique_lock<mutex> lock2;
lock2.swap(lock1); //交换控制权
//lock2.lock(); //lock1原本是锁着的,交还给lock2还是锁着的,再锁的话,就死锁了
count++;
unique_lock<mutex> lock3(std::move(lock2)); //转移lock2的控制权给lock3
//lock3.lock(); //lock2原本是锁着的,移动构造给lock3后还是锁着的,再锁的话,就死锁了
count++;
unique_lock<mutex> lock4;
lock4 = std::move(lock3); //右值引用
//lock4.lock(); //lock3原本是锁着的,移动赋值给lock4后还是锁着的,再锁的话,就死锁了
count++;
cout << count << endl;
}
};
三、unique_lock主要源码
template<class _Mutex> class unique_lock
{
public:
typedef unique_lock<_Mutex> _Myt;
typedef _Mutex mutex_type;
// CONSTRUCT, ASSIGN, AND DESTROY
unique_lock() _NOEXCEPT
: _Pmtx(0), _Owns(false)
{
// default construct
}
explicit unique_lock(_Mutex& _Mtx)
: _Pmtx(&_Mtx), _Owns(false)
{
// construct and lock
_Pmtx->lock();
_Owns = true;
}
unique_lock(unique_lock&& _Other) _NOEXCEPT //定义了移动构造函数,用来转移控制权
: _Pmtx(_Other._Pmtx), _Owns(_Other._Owns)
{
// destructive copy
_Other._Pmtx = 0;
_Other._Owns = false;
}
unique_lock& operator=(unique_lock&& _Other) //
{
// destructive copy
if (this != &_Other)
{
// different, move contents
if (_Owns)
_Pmtx->unlock();
_Pmtx = _Other._Pmtx;
_Owns = _Other._Owns;
_Other._Pmtx = 0;
_Other._Owns = false;
}
return (*this);
}
~unique_lock() _NOEXCEPT
{
// clean up
if (_Owns)
_Pmtx->unlock();
}
unique_lock(const unique_lock&) = delete; //删除了拷贝构造函数
unique_lock& operator=(const unique_lock&) = delete; //删除了赋值
// LOCK AND UNLOCK
void lock()
{
// lock the mutex
_Validate();
_Pmtx->lock();
_Owns = true;
}
bool try_lock()
{
// try to lock the mutex
_Validate();
_Owns = _Pmtx->try_lock();
return (_Owns);
}
void unlock()
{
// try to unlock the mutex
if (!_Pmtx || !_Owns)
_THROW_NCEE(system_error,
_STD make_error_code(errc::operation_not_permitted));
_Pmtx->unlock();
_Owns = false;
}
// MUTATE
void swap(unique_lock& _Other) _NOEXCEPT
{
// swap with _Other
_STD swap(_Pmtx, _Other._Pmtx);
_STD swap(_Owns, _Other._Owns);
}
_Mutex *release() _NOEXCEPT
{
// disconnect
_Mutex *_Res = _Pmtx;
_Pmtx = 0;
_Owns = false;
return (_Res);
}
private:
_Mutex *_Pmtx;
bool _Owns;
void _Validate() const
{
// check if the mutex can be locked
if (!_Pmtx)
_THROW_NCEE(system_error,
_STD make_error_code(errc::operation_not_permitted));
if (_Owns)
_THROW_NCEE(system_error,
_STD make_error_code(errc::resource_deadlock_would_occur));
}
};
四、unique_lock源码分析
禁用了普通的赋值和拷贝构造,来保证只要一个unique_lock拥有mutex。
提供了移动赋值和移动拷贝构造以及swap方法来转移拥有权。