欢迎大家来到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 { };
欢迎大家来到IT世界,在知识的湖畔探索吧!
3.1、std::lock_guard (C++11)
std::lock_guard 封装了一个 mutex,使用 ARII 机制,在构造函数中对 mutex 加锁,在析构函数中释放锁。可以避免出现函数返回,但是忘记释放锁的问题。
欢迎大家来到IT世界,在知识的湖畔探索吧!#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 是否获取锁。
欢迎大家来到IT世界,在知识的湖畔探索吧!/// 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://itzsg.com/49450.html