大家好,欢迎来到IT知识分享网。
3、mutex 辅助类 lock
为了方便使用互斥锁,C++ 标准库提供一系列辅助类。默认情况是构造函数中自动获取 mutex,析构函数中释放锁。另外,为了方便管理互斥锁,定义了三个辅助标志
- defer_lock_t:不调用 lock
- try_to_lock_t:调用 try_lock,不阻塞当前线程
- adopt_lock_t:不调用 lock,认为已经获取锁
/// std_mutex.h /// Do not acquire ownership of the mutex. struct defer_lock_t { explicit defer_lock_t() = default; }; /// Try to acquire ownership of the mutex without blocking. struct try_to_lock_t { explicit try_to_lock_t() = default; }; /// Assume the calling thread has already obtained mutex ownership /// and manage it. struct adopt_lock_t { explicit adopt_lock_t() = default; }; /// Tag used to prevent a scoped lock from acquiring ownership of a mutex. _GLIBCXX17_INLINE constexpr defer_lock_t defer_lock { }; /// Tag used to prevent a scoped lock from blocking if a mutex is locked. _GLIBCXX17_INLINE constexpr try_to_lock_t try_to_lock { }; /// Tag used to make a scoped lock take ownership of a locked mutex. _GLIBCXX17_INLINE constexpr adopt_lock_t adopt_lock { };
3.1、std::lock_guard (C++11)
std::lock_guard 封装了一个 mutex,使用 ARII 机制,在构造函数中对 mutex 加锁,在析构函数中释放锁。可以避免出现函数返回,但是忘记释放锁的问题。
#include <mutex> #include <thread> class ThreadSafeCounter { public: ThreadSafeCounter() = default; unsigned int get() const { std::lock_guard<std::mutex> lock(mutex_); return value_; } void increment() { std::lock_guard<std::mutex> lock(mutex_); ++value_; } void reset() { std::lock_guard<std::mutex> lock(mutex_); value_ = 0; } private: mutable std::mutex mutex_; unsigned int value_{}; };
std::lock_guard 是一个模板类,比较简单,定义如下:
/// std_mutex.h template<typename _Mutex> class lock_guard { public: typedef _Mutex mutex_type; // ctor 中获取 mutex explicit lock_guard(mutex_type& __m) : _M_device(__m) { _M_device.lock(); } // ctor 中不获取 mutex,user 在合适的时候获取锁 lock_guard(mutex_type& __m, adopt_lock_t) noexcept : _M_device(__m) { } // calling thread owns mutex ~lock_guard() { _M_device.unlock(); } lock_guard(const lock_guard&) = delete; lock_guard& operator=(const lock_guard&) = delete; private: mutex_type& _M_device; };
3.2、std::unique_lock (C++11)
std::unique_lock 是一个比较通用的 mutex 管理类,其实是封装了一个 Mutex,新增加了一个功能:如果获取到锁,析构函数自动释放锁。其他接口都是 Mutex 具有的接口。
std::unique_lock 另外的一个作用是,和 std::condition_variable 结合使用。
std::unique_lock 具有两个成员变量:M_device 和 M_owns。M_device 是一个指针,指向 user 指定的 Mutex 对象,M_owns 是一个 bool 类型变量,表示当前 std::unique_lock 是否获取锁。
/// unique_lock.h 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; } // defer_lock,延迟 lock unique_lock(mutex_type& __m, defer_lock_t) noexcept : _M_device(std::__addressof(__m)), _M_owns(false) { } // 调用 try_lock,不阻塞当前调用线程 unique_lock(mutex_type& __m, try_to_lock_t) : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock()) { } // 不 lock,认为 m 已经获取锁 unique_lock(mutex_type& __m, adopt_lock_t) noexcept : _M_device(std::__addressof(__m)), _M_owns(true) { // XXX calling thread owns mutex } template<typename _Clock, typename _Duration> unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __atime) : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock_until(__atime)) { } template<typename _Rep, typename _Period> unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __rtime) : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock_for(__rtime)) { } ~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; } } bool try_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_owns = _M_device->try_lock(); return _M_owns; } } template<typename _Clock, typename _Duration> bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime) { 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_owns = _M_device->try_lock_until(__atime); return _M_owns; } } template<typename _Rep, typename _Period> bool try_lock_for(const chrono::duration<_Rep, _Period>& __rtime) { 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_owns = _M_device->try_lock_for(__rtime); return _M_owns; } } void unlock() { if (!_M_owns) __throw_system_error(int(errc::operation_not_permitted)); else if (_M_device) { _M_device->unlock(); _M_owns = false; } } void swap(unique_lock& __u) noexcept { std::swap(_M_device, __u._M_device); std::swap(_M_owns, __u._M_owns); } // 放弃管理 Mutex mutex_type* release() noexcept { mutex_type* __ret = _M_device; _M_device = 0; _M_owns = false; return __ret; } // unique_lock 是否获取到锁 bool owns_lock() const noexcept { return _M_owns; } explicit operator bool() const noexcept { return owns_lock(); } mutex_type* mutex() const noexcept { return _M_device; } private: mutex_type* _M_device; bool _M_owns; };
3.3、std::shared_lock (C++14)
std::shared_lock 和 std::unique_lock 功能相似,如果对应到 std::shared_mutex,则 std::shared_lock 管理 shared 接口,而 unique_lock 管理的是 exclusive 的接口。
///shared_mutex class shared_lock { public: typedef _Mutex mutex_type; // Shared locking shared_lock() noexcept : _M_pm(nullptr), _M_owns(false) { } explicit shared_lock(mutex_type& __m) : _M_pm(std::__addressof(__m)), _M_owns(true) { __m.lock_shared(); } shared_lock(mutex_type& __m, defer_lock_t) noexcept : _M_pm(std::__addressof(__m)), _M_owns(false) { } shared_lock(mutex_type& __m, try_to_lock_t) : _M_pm(std::__addressof(__m)), _M_owns(__m.try_lock_shared()) { } shared_lock(mutex_type& __m, adopt_lock_t) : _M_pm(std::__addressof(__m)), _M_owns(true) { } template<typename _Clock, typename _Duration> shared_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __abs_time) : _M_pm(std::__addressof(__m)), _M_owns(__m.try_lock_shared_until(__abs_time)) { } template<typename _Rep, typename _Period> shared_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __rel_time) : _M_pm(std::__addressof(__m)), _M_owns(__m.try_lock_shared_for(__rel_time)) { } ~shared_lock() { if (_M_owns) _M_pm->unlock_shared(); } shared_lock(shared_lock const&) = delete; shared_lock& operator=(shared_lock const&) = delete; shared_lock(shared_lock&& __sl) noexcept : shared_lock() { swap(__sl); } shared_lock& operator=(shared_lock&& __sl) noexcept { shared_lock(std::move(__sl)).swap(*this); return *this; } void lock() { _M_lockable(); _M_pm->lock_shared(); _M_owns = true; } bool try_lock() { _M_lockable(); return _M_owns = _M_pm->try_lock_shared(); } template<typename _Rep, typename _Period> bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time) { _M_lockable(); return _M_owns = _M_pm->try_lock_shared_for(__rel_time); } template<typename _Clock, typename _Duration> bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time) { _M_lockable(); return _M_owns = _M_pm->try_lock_shared_until(__abs_time); } void unlock() { if (!_M_owns) __throw_system_error(int(errc::resource_deadlock_would_occur)); _M_pm->unlock_shared(); _M_owns = false; } // Setters void swap(shared_lock& __u) noexcept { std::swap(_M_pm, __u._M_pm); std::swap(_M_owns, __u._M_owns); } mutex_type* release() noexcept { _M_owns = false; return std::__exchange(_M_pm, nullptr); } // Getters bool owns_lock() const noexcept { return _M_owns; } explicit operator bool() const noexcept { return _M_owns; } mutex_type* mutex() const noexcept { return _M_pm; } private: void _M_lockable() const { if (_M_pm == nullptr) __throw_system_error(int(errc::operation_not_permitted)); if (_M_owns) __throw_system_error(int(errc::resource_deadlock_would_occur)); } mutex_type* _M_pm; bool _M_owns; };
3.4、std::scoped_lock (C++17)
std::scoped_lock 其实是 std::lock_guard 的拓展:std::lock_guard 只能管理单个 Mutex,而 std::scoped_lock 可以管理多个 Mutex。std::scoped_lock 可以避免死锁:按照相同的顺序 lock 和 unlock。
如果只有一个 Mutex,std::scoped_lock 和 std::lock_guard 就完全相同。
/// mutex template<typename... _MutexTypes> class scoped_lock { public: explicit scoped_lock(_MutexTypes&... __m) : _M_devices(std::tie(__m...)) { std::lock(__m...); } explicit scoped_lock(adopt_lock_t, _MutexTypes&... __m) noexcept : _M_devices(std::tie(__m...)) { } // calling thread owns mutex ~scoped_lock() { std::apply([](auto&... __m) { (__m.unlock(), ...); }, _M_devices); } scoped_lock(const scoped_lock&) = delete; scoped_lock& operator=(const scoped_lock&) = delete; private: tuple<_MutexTypes&...> _M_devices; }; template<> class scoped_lock<> { public: explicit scoped_lock() = default; explicit scoped_lock(adopt_lock_t) noexcept { } ~scoped_lock() = default; scoped_lock(const scoped_lock&) = delete; scoped_lock& operator=(const scoped_lock&) = delete; }; template<typename _Mutex> class scoped_lock<_Mutex> { public: using mutex_type = _Mutex; explicit scoped_lock(mutex_type& __m) : _M_device(__m) { _M_device.lock(); } explicit scoped_lock(adopt_lock_t, mutex_type& __m) noexcept : _M_device(__m) { } // calling thread owns mutex ~scoped_lock() { _M_device.unlock(); } scoped_lock(const scoped_lock&) = delete; scoped_lock& operator=(const scoped_lock&) = delete; private: mutex_type& _M_device; };
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/52954.html