.是否有 C++11 等价物boost::shared_mutex
?或者在 C++11 中处理多读/单写情况的另一种解决方案?
3 回答
我尝试过但未能shared_mutex
进入 C++11。它已被提议用于未来的标准。建议在这里。
编辑: C++14接受了修订版 (N3659) 。
这是一个实现:
很简单……没有。读写锁没有标准的 C++ 实现。
但是,您有几个选择。
使用#1并实现自己的任务是一项可怕的任务,如果你做的不对,你的代码可能会出现竞争条件。有一个参考实现可能会使工作更容易一些。
如果您想要独立于平台的代码,或者不想在代码中包含任何额外的库来实现像读写器锁这样简单的东西,您可以将#2扔出窗口。
而且,#3有一些大多数人没有意识到的警告:使用读写锁通常性能较差,并且与使用简单互斥锁的等效实现相比,使用的代码更难理解。这是因为必须在读写锁实现的幕后进行额外的簿记。
我只能向您展示您的选择,实际上由您来衡量每种选择的成本和收益并选择最有效的选择。
编辑:
C++17 现在有一种shared_mutex
类型,用于具有多个并发读取器的好处超过其shared_mutex
本身的性能成本的情况。
boost::shared_mutex
不,在 C++11中没有等效的 for 。
但是,C++14 或更高版本支持读/写锁:
- 添加了 C++14
std::shared_timed_mutex
- 添加了 C++17
std::shared_mutex
不同之处在于std::shared_timed_mutex
增加了额外的计时操作。它实现了SharedTimedMutex 概念,它是由实现的更简单的TimedMutex 概念std::shared_mutex
的扩展。
请记住,为读/写互斥锁获取锁比获取普通的std::mutex
. 因此,如果您有频繁但短暂的读取操作,读/写互斥锁不会提高性能。它更适合读取操作频繁且昂贵的场景。引用安东尼威廉姆斯的帖子:
锁定 shared_mutex 的成本高于锁定普通 std::mutex 的成本,即使对于读取线程也是如此。这是功能的必要部分 --- shared_mutex 的可能状态比互斥锁多,代码必须正确处理它们。此成本来自对象的大小(在您的实现和我的 POSIX 实现中都包括普通互斥锁和条件变量),以及锁定和解锁操作的性能。
此外,shared_mutex 是一个争论点,因此不可扩展。锁定 shared_mutex 必然会修改 mutex 的状态,即使对于读锁也是如此。因此,必须将保持 shared_mutex 状态的高速缓存行传输到正在执行锁定或解锁操作的处理器。
If you have a lot of threads performing frequent, short read operations, then on a multiprocessor system this can lead to a lot of cache ping-pong, which will considerably impact the performance of the system. In this case, you may as well adopt the simpler design of just using a plain mutex, as the readers are essentially serialized anyway.
If the reads are not frequent, then there is no contention, so you don't need to worry about concurrent readers, and a plain mutex will suffice for that scenario anyway.
If the read operations are time consuming, then the consequence of this contention is less visible, since it is dwarfed by the time spent whilst holding the read lock. However, performing time consuming operations whilst holding a lock is a design smell.
In the vast majority of cases, I think that there are better alternatives to a shared_mutex. These may be a plain mutex, the atomic support of shared_ptr, the use of a carefully constructed concurrent container, or something else, depending on context.