《C++ Concurrency in Action》笔记9 std::unique_lock源码分析

std::unique_lock提供与std::lock_guard 相同的RAII -style锁管理机制,但是更加灵活。要想理解unique_lock,最好的办法就是看他的源码(vs2013):

template<class _Mutex>
	class unique_lock
	{	// whizzy class with destructor that unlocks mutex
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(_Mutex& _Mtx, adopt_lock_t)
		: _Pmtx(&_Mtx), _Owns(true)
		{	// construct and assume already locked
		}

	unique_lock(_Mutex& _Mtx, defer_lock_t) _NOEXCEPT
		: _Pmtx(&_Mtx), _Owns(false)
		{	// construct but don't lock
		}

	unique_lock(_Mutex& _Mtx, try_to_lock_t)
		: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock())
		{	// construct and try to lock
		}

	template<class _Rep,
		class _Period>
		unique_lock(_Mutex& _Mtx,
			const chrono::duration<_Rep, _Period>& _Rel_time)
		: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock_for(_Rel_time))
		{	// construct and lock with timeout
		}

	template<class _Clock,
		class _Duration>
		unique_lock(_Mutex& _Mtx,
			const chrono::time_point<_Clock, _Duration>& _Abs_time)
		: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock_until(_Abs_time))
		{	// construct and lock with timeout
		}

	unique_lock(_Mutex& _Mtx, const xtime *_Abs_time)
		: _Pmtx(&_Mtx), _Owns(false)
		{	// try to lock until _Abs_time
		_Owns = _Pmtx->try_lock_until(_Abs_time);
		}

	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);
		}

	template<class _Rep,
		class _Period>
		bool try_lock_for(const chrono::duration<_Rep, _Period>& _Rel_time)
		{	// try to lock mutex for _Rel_time
		_Validate();
		_Owns = _Pmtx->try_lock_for(_Rel_time);
		return (_Owns);
		}

	template<class _Clock,
		class _Duration>
		bool try_lock_until(
			const chrono::time_point<_Clock, _Duration>& _Abs_time)
		{	// try to lock mutex until _Abs_time
		_Validate();
		_Owns = _Pmtx->try_lock_until(_Abs_time);
		return (_Owns);
		}

	bool try_lock_until(const xtime *_Abs_time)
		{	// try to lock the mutex until _Abs_time
		_Validate();
		_Owns = _Pmtx->try_lock_until(_Abs_time);
		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);
		}

	// OBSERVE
	bool owns_lock() const _NOEXCEPT
		{	// return true if this object owns the lock
		return (_Owns);
		}

	explicit operator bool() const _NOEXCEPT
		{	// return true if this object owns the lock
		return (_Owns);
		}

	_Mutex *mutex() const _NOEXCEPT
		{	// return pointer to managed mutex
		return (_Pmtx);
		}

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));
		}
	};

	// SWAP
template<class _Mutex>
	void swap(unique_lock<_Mutex>& _Left,
		unique_lock<_Mutex>& _Right) _NOEXCEPT
	{	// swap _Left and _Right
	_Left.swap(_Right);
	}

虽然看起来很长,但是其实很容易理解。他基本的特点就是:

1.不可以拷贝构造、不可以拷贝赋值。但是可以移动构造和赋值,可以swap。

2.是个类模板,具体操作由指定的模板参数决定。

3.成员变量包括一个指向mutex的指针_Pmtx,还有一个代表是否已经锁定了当前mutex的bool量_Owns。

4.构造时可以指定构造函数的做出不同行为。

下面对几个关键的函数做简单介绍:

explicit unique_lock(_Mutex& _Mtx) : _Pmtx(&_Mtx), _Owns(false)
{	// construct and lock
	_Pmtx->lock();
	_Owns = true;
}
构造时直接锁定mutex。

	unique_lock(_Mutex& _Mtx, adopt_lock_t)
		: _Pmtx(&_Mtx), _Owns(true)
		{	// construct and assume already locked
		}
构造时认为mutex已经被锁定,不再重复锁定。

	unique_lock(_Mutex& _Mtx, defer_lock_t) _NOEXCEPT
		: _Pmtx(&_Mtx), _Owns(false)
		{	// construct but don't lock
		}
构造时认为mutex没有被锁定,而且暂时不执行锁定操作。可以在之后的代码中执行lock()、try_lock、try_lock_for、try_lock_util等操作。注意,std::mutex不支持try_lock_for、try_lock_util操作,std::timed_mutex和std::recursive_mutex支持这两种操作。

	unique_lock(_Mutex& _Mtx, try_to_lock_t)
		: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock())
		{	// construct and try to lock
		}
构造时直接使用mutex的try_lock()函数。

	template<class _Rep,
		class _Period>
		unique_lock(_Mutex& _Mtx,
			const chrono::duration<_Rep, _Period>& _Rel_time)
		: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock_for(_Rel_time))
		{	// construct and lock with timeout
		}
构造时使用mutex的try_lock_for函数,指定最大时间。

	template<class _Clock,
        class _Duration>
        unique_lock(_Mutex& _Mtx,
            const chrono::time_point<_Clock, _Duration>& _Abs_time)
        : _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock_until(_Abs_time))
        {    // construct and lock with timeout
        }

    unique_lock(_Mutex& _Mtx, const xtime *_Abs_time)
        : _Pmtx(&_Mtx), _Owns(false)
        {    // try to lock until _Abs_time
        _Owns = _Pmtx->try_lock_until(_Abs_time);
        }
构造时使用mutex的try_lock_uti()函数,指定一个绝对时间点。

	_Mutex *release() _NOEXCEPT
		{	// disconnect
		_Mutex *_Res = _Pmtx;
		_Pmtx = 0;
		_Owns = false;
		return (_Res);
		}
release()函数代表直接返回其保存的mutex指针,并且将对象状态清空。在此期间不对mutex做锁定或解锁操作。

	bool owns_lock() const _NOEXCEPT
		{	// return true if this object owns the lock
		return (_Owns);
		}

	explicit operator bool() const _NOEXCEPT
		{	// return true if this object owns the lock
		return (_Owns);
		}

owns_lock()和bool类型转换函数都代表当前mutex是否已经被锁定。

	_Mutex *mutex() const _NOEXCEPT
		{	// return pointer to managed mutex
		return (_Pmtx);
		}
直接返回内部保存的mutex指针,不做状态清理工作。比较危险,轻易不要使用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值