锁的理解:提供了以排他方式防止数据结构被并发修改的方法。
mutex类源码
class _Mutex_base
{ // base class for all mutex types
public:
_Mutex_base(int _Flags = 0) noexcept;
~_Mutex_base() noexcept;
_Mutex_base(const _Mutex_base&) = delete;
_Mutex_base& operator=(const _Mutex_base&) = delete;
void lock();
_NODISCARD bool try_lock();
void unlock();
typedef void *native_handle_type;
_NODISCARD native_handle_type native_handle();
private:
friend condition_variable;
friend condition_variable_any;
aligned_storage_t<_Mtx_internal_imp_size,
_Mtx_internal_imp_alignment> _Mtx_storage;
_Mtx_t _Mymtx() noexcept;
};
class mutex
: public _Mutex_base
{ // class for mutual exclusion
public:
/* constexpr */ mutex() noexcept // TRANSITION
: _Mutex_base()
{ // default construct
}
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;
};
类属性和接口说明
1、#include //头文件
2、std::mutex my_mutex; //创建对象,构造
3、my_mutex.lock(); //加锁,基类方法
4、my_mutex.unlock(); //解锁,基类方法
5、my_mutex.try_lock(); //尝试给互斥量加锁,返回值为是否拿到锁,基类方法
6、mutex类和其基类均无拷贝、拷贝赋值语义
7、nativehandle函数允许使用平台API直接操作低层实现,一般不使用。基类私有成员非外包接口,暂时不研究
lock_guard类源码
template<class _Mutex>
class lock_guard
{ // class with destructor that unlocks a mutex
public:
using mutex_type = _Mutex;
explicit lock_guard(_Mutex& _Mtx)
: _MyMutex(_Mtx)
{ // construct and lock
_MyMutex.lock();
}
lock_guard(_Mutex& _Mtx, adopt_lock_t)
: _MyMutex(_Mtx)
{ // construct but don't lock
}
~lock_guard() noexcept
{ // unlock
_MyMutex.unlock();
}
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete;
private:
_Mutex& _MyMutex;
};
类属性和接口说明
1、可直接取代lock()和unlock(),不需要加锁和解锁组合使用
//创建方式
std::lock_guard<std::mutex> sbguard(my_mutex);
2、创建时调用lock(),出作用域析构调用unlock()
3、可选第二构造参数std::adopt_lock_t类型,不上锁构造函数(构造内不调用lock()),说明互斥量mutex已经lock
4、无拷贝、拷贝赋值语义
1、发生情况:
线程A被互斥锁1锁住,正要去lock锁2,线程B被互斥锁2锁住,正要去lock锁1;
线程A会等锁2unlock,线程B会等锁1unlock,此时则发生死锁。
2、处理方法:
保持锁的顺序一致,或者不在一块代码交织,单个锁则不会发生死锁
std::lock()函数模板锁定多个锁,但没有死锁。
std::lock()与mutex对象搭配还需手动unlock()。
std::lock()与lock_guard类模板搭配使用,需要调用传入std::adopt_lock_t 类型的第二参数的不上锁构造函数,因为std::lock()时已上锁。
3、避免死锁方法
1)避免嵌套锁
2)在持有锁时,避免调用用户提供代码
3)以固定的顺序获取锁
4)使用层次锁
4、锁属性标记
1)struct adopt_lock_t;//表明已采用锁
前提是已经lock。
2)struct defer_lock_t;//表明推迟锁
初始化了一个没有加锁的mutex。
前提是没先lock。
3)struct try_to_lock_t;//表示试图锁定
尝试用mutex的lock()去锁定这个mutex,但如果没有锁定成功,会立即返回,并不阻塞。前提是没先lock。
_INLINE_VAR constexpr adopt_lock_t adopt_lock{};
_INLINE_VAR constexpr defer_lock_t defer_lock{};
_INLINE_VAR constexpr try_to_lock_t try_to_lock{};
unique_lock类源码
template<class _Mutex>
class unique_lock
{ // whizzy class with destructor that unlocks mutex
public:
typedef _Mutex mutex_type;
// CONSTRUCT, ASSIGN, AND DESTROY
unique_lock() noexcept
: _Pmtx(nullptr), _Owns(false)
{ // default construct
}
explicit unique_lock(_Mutex& _Mtx)
: _Pmtx(_STD addressof(_Mtx)), _Owns(false)
{ // construct and lock
_Pmtx->lock();
_Owns = true;
}
unique_lock(_Mutex& _Mtx, adopt_lock_t)
: _Pmtx(_STD addressof(_Mtx)), _Owns(true)
{ // construct and assume already locked
}
unique_lock(_Mutex& _Mtx, defer_lock_t) noexcept
: _Pmtx(_STD addressof(_Mtx)), _Owns(false)
{ // construct but don't lock
}
unique_lock(_Mutex& _Mtx, try_to_lock_t)
: _Pmtx(_STD addressof(_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(_STD addressof(_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(_STD addressof(_Mtx)), _Owns(_Pmtx->try_lock_until(_Abs_time))
{ // construct and lock with timeout
}
unique_lock(_Mutex& _Mtx, const xtime *_Abs_time)
: _Pmtx(_STD addressof(_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 = nullptr;
_Other._Owns = false;
}
unique_lock& operator=(unique_lock&& _Other)
{ // destructive copy
if (this != _STD addressof(_Other))
{ // different, move contents
if (_Owns)
_Pmtx->unlock();
_Pmtx = _Other._Pmtx;
_Owns = _Other._Owns;
_Other._Pmtx = nullptr;
_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;
void lock()
{ // lock the mutex
_Validate();
_Pmtx->lock();
_Owns = true;
}
_NODISCARD bool try_lock()
{ // try to lock the mutex
_Validate();
_Owns = _Pmtx->try_lock();
return (_Owns);
}
template<class _Rep,
class _Period>
_NODISCARD 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>
_NODISCARD 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);
}
_NODISCARD 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(system_error(
_STD make_error_code(errc::operation_not_permitted)));
_Pmtx->unlock();
_Owns = false;
}
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 = nullptr;
_Owns = false;
return (_Res);
}
_NODISCARD 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);
}
_NODISCARD _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(system_error(
_STD make_error_code(errc::operation_not_permitted)));
if (_Owns)
_THROW(system_error(
_STD make_error_code(errc::resource_deadlock_would_occur)));
}
};
类属性和接口说明
1、对模板参数_Mutex对象进行了托管,并增加一个bool值(加锁的标记)。
2、可支持多种方式(空、构造内lock、第二参数为三种锁标记、接受超时时间类参数、move语义…)的构造,析构内根据加锁标记调用unlock()。
3、创建类模板对象
std::unique_lock<std::mutex> un_lock(my_mutex);
4、可直接取代lock_guard类模板,非常灵活,更复杂,效率略低。
5、无拷贝、拷贝赋值语义,但有move语义
6、接口说明
void lock();//上锁
void unlock();//解锁
bool try_lock();//尝试给互斥量加锁,返回值为是否拿到锁,该函数不阻塞
void swap(unique_lock& _Other) noexcept;//交换锁
_Mutex *release() noexcept;//返回它所管理的mutex对象指针,并释放所有权;接受返回值对象责任接管,并负责解锁
bool owns_lock() const noexcept;//判断是否拿到了锁
explicit operator bool() const noexcept;//判断是否拿到了锁
bool try_lock_for(); //可接受超时参数,返回是否拿到了锁
bool try_lock_until(); //可接受超时参数,返回是否拿到了锁
在多线程中保证第二参数(可调用对象:函数、lambda表达式等)只被执行一次
std::once_flag m_flag; //搭配使用
std::call_once(m_flag, CreateInstance);
使用示例请见:单例模式singleton->三.4:https://blog.csdn.net/qq_43148810/article/details/104957327
如有错误或不足欢迎评论指出!创作不易,转载请注明出处。如有帮助,记得点赞关注哦(⊙o⊙)
更多内容请关注个人博客:https://blog.csdn.net/qq_43148810