C++11中与boost shared_mutex相当的内容

57

在C++11中是否有与boost::shared_mutex相当的东西?或者有其他解决方案可以处理C++11中的多读/单写情况吗?


16
boost::shared_mutex被标准化委员会拒绝了。这可能与此相关:http://permalink.gmane.org/gmane.comp.lib.boost.devel/211180 - Andy Prowl
3
我同意Nawaz的观点。 - Matthieu M.
4
同意共享锁并不适用于需要持有锁的时间非常短的情况。但这并非总是可能的。如果可以的话,共享锁在许多库和语言中就不会如此普遍。 - Howard Hinnant
3
如果我们要站队,我站在霍华德这边。特别是我认为,“在持有锁的同时执行耗时操作是设计上的一个坏味道”这一说法完全不可信。如果“设计上的坏味道”意味着“绝不能发生的事情”,那么根据我的经验,它肯定是错误的(考虑到“足以避免严重的缓存乒乓”的时间不是消耗的太多)。否则,“设计上的坏味道”意味着“可能存在问题的令人担忧的迹象,但在某些情况下仍然是必要的东西”,那么为什么通过从建议中删除rwlock来撤回对这些情况的支持呢? - Steve Jessop
5
@Nawaz:但这只是一个论点,即存在某些情况下,读写锁不比互斥锁更好(在其他地方,Williams 解释了为什么有时候它更糟)。这是正确的,但这并不是移除读写锁的好理由。你可能也可以基于“有时候” deque 更好的理由移除 vector。我并不是说委员会没有充分的理由不包括 shared_mutex,只是这个解释(我希望)不是全部。有时候,被锁住的操作比缓存刷新慢一个数量级,因此并不受读写锁的序列化保护,但这并不意味着它们是“有问题的”。 - Steve Jessop
显示剩余6条评论
3个回答

71

2
shared_timed_mutex 在 C++14 中引入;shared_mutex 看起来将在 C++1z 中出现(事实证明,通过放弃时间能力可以获得效率提升)。 - Yakk - Adam Nevraumont

19

简单来说……并没有标准的C++ 读写锁 实现。

不过你有几个选择:

  1. 自己动手实现一个读写锁。
  2. 使用平台特定的实现,例如 Win32POSIX 或者 Boost 中提到的。
  3. 完全不使用读写锁——而是使用 C++11 中已经存在的 互斥量

使用#1并自行实现可能会让人感到害怕,如果您做得不好可能会在代码中引入竞态条件。有一个参考实现可能会使工作变得更容易一些。

如果您想要平台无关的代码或者不想在代码中包含任何额外的库来实现诸如读写锁这样简单的东西,可以放弃#2

而且,#3有几个注意事项大多数人都没有意识到:使用读写锁通常性能较差,并且具有比使用简单互斥锁等价实现更难理解的代码。这是因为读写锁实现背后需要进行额外的簿记处理。


我只能向您展示选项,真正的决定权在于您权衡每个选项的成本和收益,并选择最适合您的。


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

13

在C++11中没有与boost::shared_mutex等效的东西。

然而,在C++14及以后版本中支持读写锁:

两者之间的区别是std::shared_timed_mutex添加了更多的时间操作。它实现了SharedTimedMutex概念,该概念是std::shared_mutex实现的简单TimedMutex概念的扩展。


请记住,获取读写锁的锁比获取普通的std::mutex的锁更加昂贵。因此,如果您经常进行短时间的读操作,则读写锁不会提高性能。它更适合于频繁且昂贵的读操作。引用Anthony Williams的文章

即使对于读取线程,锁定shared_mutex的成本也比锁定简单std::mutex要高。这是功能的必要部分---shared_mutex可能的状态比mutex更多,代码必须正确处理它们。这个成本体现在对象的大小上(在您和我在POSIX中的实现中都包括简单的mutex和条件变量),以及锁定和解锁操作的性能方面。

另外,shared_mutex是一个争用点,因此不可扩展。对shared_mutex进行锁定必然会修改mutex的状态,即使是读锁也是一样。因此,持有shared_mutex状态的缓存行必须传输到执行锁定或解锁操作的任何处理器。
如果有大量线程执行频繁且短暂的读操作,则在多处理器系统上,这可能会导致大量的缓存ping-pong,这将极大地影响系统性能。在这种情况下,您可以采用更简单的设计,只使用普通互斥锁,因为读取器实际上已经串行化了。
如果读取不频繁,则没有争用,因此您不需要担心并发读取,普通互斥锁就足够了。
如果读取操作耗时,则这种争用的后果就不那么明显了,因为它被持有读锁的时间所淹没。但是,在持有锁定的同时执行耗时操作是一种设计上的问题。
在绝大多数情况下,我认为有比shared_mutex更好的选择。这些可能是普通互斥锁、shared_ptr的原子支持、使用精心构建的并发容器或其他内容,具体取决于上下文。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接