std :: mutex和std :: shared_mutex之间的区别

asa*_*itp 12 c++ mutex c++11 c++17

我碰到一个std::shared_mutexC++17.究竟是什么std::shared_mutex以及它与众不同std::mutex

Cor*_*mer 13

文档所述

shared_mutex类是一个同步原语,可用于保护共享数据不被多个线程同时访问.与其他便于独占访问的互斥锁类型相比,shared_mutex具有两个访问级别:

  • 共享 - 多个线程可以共享同一个互斥锁的所有权.
  • 独占 - 只有一个线程可以拥有互斥锁.

共享互斥锁通常用于多个读者可以同时访问同一资源而不会导致数据争用的情况,但只有一个编写者可以这样做.

这有多种用途,但一个常见的用途是实现一个Read Write Lock,你可以让多个线程读取共享数据,但只有一个线程可以随时独占写入.因此,当您有多个读卡器时,互斥锁将以"共享模式"运行,但是当请求写入时,它将变为"独占模式".


Yak*_*ont 8

Amutex要么被锁定,要么没有。

Ashared_mutex要么被独占锁定,要么被锁定共享,或者没有被锁定。

任意数量的客户端都可以共享一个共享互斥锁。

如果有人排它锁,其他人就不能持有任何锁。

在windows上,就是这种SWRLOCK类型——事实上,这个锁通常用于实现读写锁;许多读者允许,但写作必须是排他性的。

下面是一些示例代码,用于为共享和非共享互斥锁创建两个模板包装器。在一种情况下,我们有需要不同锁的读写操作。另一方面,我们只能访问:

template<class T, class M=std::mutex>
struct mutex_guarded {
  template<class F>
  auto access( F&& f ) {
    auto l = lock();
    return std::forward<F>(f)(t);
  }
  template<class F>
  auto access( F&& f ) const {
    auto l = lock();
    return std::forward<F>(f)(t);
  }
  mutex_guarded(mutex_guarded const&)=delete;
  mutex_guarded& operator=(mutex_guarded const&)=delete;
  template<class...Ts>
  mutex_guarded( Ts&&...ts ):t(std::forward<Ts>(ts)...){}
  mutex_guarded()=default;
protected:
  mutable M m;
  T t;
  auto lock() { return std::unique_lock<M>(m); }
};
template<class T, class M=std::shared_mutex>
struct shared_mutex_guarded:private mutex_guarded<T, M> {
  using base = mutex_guarded<T, M>;
  template<class F>
  auto read( F&& f ) const { return access(std::forward<F>(f)); }
  template<class F>
  auto write( F&& f ) { return access(std::forward<F>(f)); }

  using base::base;
protected:
  using base::access;
  template<class F>
  auto access( F&& f ) const {
    auto l = lock();
    return std::forward<F>(f)(this->t);
  }
  using base::lock;
  auto lock() const { return std::shared_lock<M>(this->m); }
};
Run Code Online (Sandbox Code Playgroud)


Sau*_*ahu 5

std::shared_mutex特别是在数据结构(如 DNS 缓存)很少更新的情况下非常有用。使用 astd::mutex来保护数据结构可能过于悲观,因为它消除了当数据结构未进行修改时\n读取数据结构时可能的并发性。std::shared_mutex多个线程可以同时拥有同一个线程的共享锁。

\n\n

安东尼·威廉姆斯(Anthony Williams)书中的一个这样的例子:

\n\n
class dns_cache\n{\n    std::map<std::string,dns_entry> entries;\n    mutable boost::shared_mutex entry_mutex;\n\npublic:\n\n    dns_entry find_entry(std::string const& domain) const\n    {\n        boost::shared_lock<boost::shared_mutex> lk(entry_mutex);\n        std::map<std::string,dns_entry>::const_iterator const it = entries.find(domain);\n        return (it==entries.end()) ? dns_entry() : it->second;\n    }\n\n    void update_or_add_entry(std::string const& domain,\n                            dns_entry const& dns_details)\n    {\n        std::lock_guard<boost::shared_mutex> lk(entry_mutex);\n        entries[domain] = dns_details;\n    }\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里,函数find_entry基本上执行读取操作,而update_or_add_entry执行写入操作。

\n\n

因此,可以说这std::shared_mutex是一个典型的读写器互斥体,因为它允许\n两种不同的用法:单个 \xe2\x80\x9cwriter\xe2\x80\x9d 线程的独占访问或共享,\n并发访问多个 \xe2\x80\x9creader\xe2\x80\x9d 线程。

\n