C++ 多线程编程系列 | 析构释放锁 lock

C++ 多线程编程系列 | 析构释放锁 lock3、mutex 辅助类 lock为了方便使用互斥锁,C++ 标准库提供一系列辅助类。默认情况是构造函数中自动获取 mutex,析构函数中释放锁。

欢迎大家来到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

(0)
上一篇 2024年 4月 27日 下午7:23
下一篇 2024年 5月 1日 上午8:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信