【问题标题】:C++11 equivalent to boost shared_mutexC++11 相当于 boost shared_mutex
【发布时间】:2012-12-27 17:24:33
【问题描述】:

boost::shared_mutex 是否有 C++11 等效项。或者在 C++11 中处理多读/单写情况的另一种解决方案?

【问题讨论】:

  • boost::shared_mutex 被标准化委员会否决。这可能是相关的:permalink.gmane.org/gmane.comp.lib.boost.devel/211180
  • @AndyProwl:我支持 Nawaz。
  • 同意共享锁定不是一个很好的解决方案,因为您可以持有一小段时间的锁。但这并不总是可能的。如果是这样,共享锁定就不会在这么多库和语言中如此普遍。
  • 如果我们选边站,我会支持霍华德。特别是,我发现“在持有锁时进行耗时的操作是一种设计气味”,完全没有说服力。要么“设计气味”意味着“绝对不能发生的事情”,在这种情况下,它肯定是错误的 IME(考虑到“足以避免严重的缓存乒乓”不是 很多消费),或者“设计气味”意味着“一个令人担忧的迹象,表明可能存在问题,但在某些情况下仍然是必要的”,在这种情况下,为什么要通过从提案中删除 rwlocks 来撤回对这些情况的支持?跨度>
  • @Nawaz:但这只是一个论点,即存在 rwlock 并不比互斥锁更好的情况(Willams 在其他地方解释了为什么有时情况更糟)。这是真的,但这不是删除 rwlocks 的好理由。您不妨删除vector,因为有时 deque 更好。我并不是说委员会没有充分的理由不包括shared_mutex,只是这个解释不是(我希望)它的全部。有时您的锁定操作比缓存刷新慢一个数量级,因此 not 由 rwlock 序列化。不会让它们“臭”。

标签: c++ boost c++11 mutex


【解决方案1】:

我尝试过但未能将shared_mutex 导入 C++11。它已被提议用于未来的标准。提案是here

编辑:针对 C++14 的修订版 (N3659) was accepted

这是一个实现:

http://howardhinnant.github.io/shared_mutex

http://howardhinnant.github.io/shared_mutex.cpp

【讨论】:

  • shared_timed_mutex 在 C++14 中; shared_mutex 看起来像是在 C++1z 中出现的(事实证明,通过放弃计时能力可以提高效率)
【解决方案2】:

简单...没有。 readers-writer 锁没有标准的 C++ 实现。

但是,您有几个选择。

  1. 您只能使用自己的设备来制作自己的读写器锁。
  2. 如您所述,使用特定于平台的实现,例如 Win32'sPOSIX'sBoost's
  3. 根本不要使用——使用 C++11 中已经存在的mutex

使用 #1 并实现您自己的任务是一项可怕的工作,如果您没有正确处理,您的代码可能会出现竞争条件。有一个reference implemenation 可能会使工作更容易一些。

如果您想要独立于平台的代码,或者不想在代码中包含任何额外的库来实现诸如读写锁之类的简单操作,您可以将 #2 扔到窗外。

而且,#3 有一些大多数人没有意识到的警告:使用读写锁通常性能较差,并且与等效实现相比,代码更难理解使用简单的互斥锁。这是因为必须在读写锁实现的幕后进行额外的簿记。


我只能向您展示您的选择,实际上,您需要权衡每个选项的成本和收益,然后选择最有效的选项。


编辑: C++17 现在有一个 shared_mutex 类型,用于具有多个并发读取器的好处超过 shared_mutex 本身的性能成本的情况。

【讨论】:

    【解决方案3】:

    不,在 C++11 中没有 boost::shared_mutex 的等价物。

    不过,C++14 或更高版本支持读/写锁:

    不同的是std::shared_timed_mutex增加了额外的定时操作。它实现了SharedTimedMutex concept,它是std::shared_mutex 实现的更简单的TimedMutex concept 的扩展。


    请记住,为读/写互斥锁获取锁比获取普通的std::mutex 更昂贵。因此,如果您有频繁但短暂的读取操作,读/写互斥锁不会提高性能。它更适合读取操作频繁且昂贵的场景。引用Anthony Williams' post:

    锁定一个 shared_mutex 的成本高于锁定一个 普通的 std::mutex,即使对于阅读器线程也是如此。这是一个必要的部分 的功能 --- 有更多可能的状态 shared_mutex 比互斥锁,并且代码必须正确处理它们。这 成本来自对象的大小(在您的 实现和我的 POSIX 实现都包括一个普通的互斥锁 和一个条件变量),并在锁定和解锁的表现 操作。

    另外,shared_mutex 是一个争论点,因此不 可扩展的。锁定 shared_mutex 必然会修改 互斥锁,即使是读锁。因此,缓存行持有 shared_mutex 状态必须转移到任何处理器 执行锁定或解锁操作。

    如果您有很多线程执行频繁、短时间的读取操作, 然后在多处理器系统上,这可能会导致大量缓存 乒乓球,这将极大地影响的性能 系统。在这种情况下,你不妨采用更简单的设计,只是 使用普通的互斥锁,因为无论如何阅读器基本上都是序列化的。

    如果读取不频繁,则不存在争用,因此您不必 需要担心并发读者,一个普通的互斥体就足够了 无论如何,对于那种情况。

    如果读取操作很耗时,那么这样做的后果 争用不太明显,因为它与花费的时间相形见绌 持有读锁。但是,执行耗时的操作 拿着锁是一种设计气味。

    在绝大多数情况下,我认为有更好的 shared_mutex 的替代品。这些可能是一个普通的互斥体,原子的 支持 shared_ptr,使用精心构造的并发 容器或其他东西,具体取决于上下文。

    【讨论】:

      猜你喜欢
      • 2014-02-02
      • 2011-03-19
      • 2013-08-27
      • 1970-01-01
      • 2013-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多