C++17 引入std::scoped_lock, 它是std::lock_guard的升级版本。
scoped_lock可以一次绑定多个mutex,保证不会死锁,
如果有多个mutex要同时lock,用scoped_lock。 如果只要lock一个mutex,可以用lock_guard,不过更建议统一用升级过后的scoped_lock。
template< class... MutexTypes > | (C++17 起) |
类 scoped_lock
是提供便利 RAII 风格机制的互斥包装器,它在作用域块的存在期间占有一或多个互斥体。
当创建 scoped_lock
对象时,它尝试取得各给定互斥体的所有权。当控制离开创建 scoped_lock
对象的作用域时,析构 scoped_lock
并释放各互斥体。若给出多个互斥体,则如同用 std::lock 使用免死锁算法。
scoped_lock
类不可复制
scoped_lock 代码实现
1. std::scoped_lock
是一个类模板,它有两个特化,
//类模板
_EXPORT_STD template <class... _Mutexes>
class _NODISCARD_LOCK scoped_lock { // class with destructor that unlocks mutexes
public:
explicit scoped_lock(_Mutexes&... _Mtxes) : _MyMutexes(_Mtxes...) { // construct and lock
_STD lock(_Mtxes...); //调用 lock, 防止死锁发生
}
explicit scoped_lock(adopt_lock_t, _Mutexes&... _Mtxes) noexcept // strengthened
: _MyMutexes(_Mtxes...) {} // construct but don't lock
~scoped_lock() noexcept {
_STD apply([](_Mutexes&... _Mtxes) _STATIC_CALL_OPERATOR { (..., (void) _Mtxes.unlock()); }, _MyMutexes);
}
scoped_lock(const scoped_lock&) = delete;
scoped_lock& operator=(const scoped_lock&) = delete;
private:
tuple<_Mutexes&...> _MyMutexes;
};
2. 对模板类型形参包只有一个类型情况的偏特化版本,等价与std::lock_guard
template <class _Mutex>
class _NODISCARD_LOCK scoped_lock<_Mutex> {
public:
using mutex_type = _Mutex;
explicit scoped_lock(_Mutex& _Mtx) : _MyMutex(_Mtx) { // construct and lock
_MyMutex.lock();
}
explicit scoped_lock(adopt_lock_t, _Mutex& _Mtx) noexcept // strengthened
: _MyMutex(_Mtx) {} // construct but don't lock
~scoped_lock() noexcept {
_MyMutex.unlock();
}
scoped_lock(const scoped_lock&) = delete;
scoped_lock& operator=(const scoped_lock&) = delete;
private:
_Mutex& _MyMutex;
};
3. 对类型形参包为空的情况的全特化,没有数据成员
template <>
class scoped_lock<> {
public:
explicit scoped_lock() = default;
explicit scoped_lock(adopt_lock_t) noexcept /* strengthened */ {}
scoped_lock(const scoped_lock&) = delete;
scoped_lock& operator=(const scoped_lock&) = delete;
};
以上三种对应的实例代码
std::mutex m1,m2;
std::scoped_lock<std::mutex> lc{ m1 }; // 匹配到偏特化版本 保有一个 std::mutex&
std::scoped_lock<std::mutex, std::mutex> lc2{ m1,m2 }; // 匹配到主模板 保有一个 std::tuple<std::mutex&,std::mutex&>
std::scoped_lock<> lc3;