Reader / Writerlocking在C ++中
我在C ++中寻找一个好的读写器锁。 我们有一个罕见的作家和许多频繁的读者的用例,并希望为此进行优化。 最好是我想要一个跨平台的解决scheme,但是只有一个Windows是可以接受的。
较新版本的boost :: thread有读/写锁(1.35.0和更高版本,显然以前的版本不能正常工作)。
它们有名称shared_lock
, unique_lock
和upgrade_lock
并在shared_mutex
。
使用标准的预先testing过的,预先build好的东西总是好的(例如,提示另一个答案的Boost),但是这不是很难build立自己的东西。 这是一个从我的项目中抽出来的一个愚蠢的小实现:
#include <pthread.h> struct rwlock { pthread_mutex_t lock; pthread_cond_t read, write; unsigned readers, writers, read_waiters, write_waiters; }; void reader_lock(struct rwlock *self) { pthread_mutex_lock(&self->lock); if (self->writers || self->write_waiters) { self->read_waiters++; do pthread_cond_wait(&self->read, &self->lock); while (self->writers || self->write_waiters); self->read_waiters--; } self->readers++; pthread_mutex_unlock(&self->lock); } void reader_unlock(struct rwlock *self) { pthread_mutex_lock(&self->lock); self->readers--; if (self->write_waiters) pthread_cond_signal(&self->write); pthread_mutex_unlock(&self->lock); } void writer_lock(struct rwlock *self) { pthread_mutex_lock(&self->lock); if (self->readers || self->writers) { self->write_waiters++; do pthread_cond_wait(&self->write, &self->lock); while (self->readers || self->writers); self->write_waiters--; } self->writers = 1; pthread_mutex_unlock(&self->lock); } void writer_unlock(struct rwlock *self) { pthread_mutex_lock(&self->lock); self->writers = 0; if (self->write_waiters) pthread_cond_signal(&self->write); else if (self->read_waiters) pthread_cond_broadcast(&self->read); pthread_mutex_unlock(&self->lock); } void rwlock_init(struct rwlock *self) { self->readers = self->writers = self->read_waiters = self->write_waiters = 0; pthread_mutex_init(&self->lock, NULL); pthread_cond_init(&self->read, NULL); pthread_cond_init(&self->write, NULL); }
pthreads
不是真正的Windows本机,但总的想法是在这里。 这个实现稍微偏向作家(一群作家可以无限期地使读者挨饿); 只要修改writer_unlock
如果你宁愿平衡是相反的。
是的,这是C而不是C ++。 翻译是留给读者的一个练习。
编辑
Greg Rogers指出,POSIX标准确实规定了pthread_rwlock_*
。 如果你没有pthreads
,这没有什么帮助,但是它激起了我的想法: Pthreads-w32应该工作! 不要将这些代码移植到非pthreads
供自己使用,只需在Windows上使用Pthreads-w32,而在其他地方使用本地pthreads
。
您可以使用boost来创build一个读写locking:
#include <boost/thread/locks.hpp> #include <boost/thread/shared_mutex.hpp> typedef boost::shared_mutex Lock; typedef boost::unique_lock< Lock > WriteLock; typedef boost::shared_lock< Lock > ReadLock; Lock myLock; void ReadFunction() { ReadLock r_lock(myLock); //Do reader stuff } void WriteFunction() { WriteLock w_lock(myLock); //Do writer stuff }
无论您决定使用哪种方法,都需要针对简单的锁进行基准testing,因为在没有争用的情况下,读取/写入locking的速度通常比简单的互斥锁慢3-40倍。
这里有一些参考
编辑:MSDN杂志链接不再可用。 CodeProject文章现在可以在https://www.codeproject.com/Articles/32685/Testing-reader-writer-locks上得到很好的总结。; 我还发现了一个关于复合同步对象的新的MSDN链接。
有一篇关于MSDN上的读写器锁的文章 ,介绍了它们的一些实现。 它还介绍了Slim reader / writer lock,这是Vista引入的一个内核同步原语。 还有一个关于比较不同实现(包括MSDN文章)的CodeProject文章 。
英特尔线程构build模块还提供了几个rw_lock变体:
http://www.threadingbuildingblocks.org/
他们有一个很短的争用时间spin_rw_mutex和较长时间的争用queueing_rw_mutex。 前者可用于特别对性能敏感的代码。 后者在性能上与Boost.Thread或直接使用pthread提供的性能相当。 但个人资料,以确保哪一个是你的访问模式的胜利。
Boost.Thread自发行版本1.35.0已经支持读写器锁。 关于这一点的好处是,这个实现是跨平台的,经过同行评审的,实际上是即将到来的C ++ 0x标准的参考实现 。
我可以推荐ACE库 ,它提供了多种locking机制,并被移植到各种平台上。
根据问题的边界条件,您可能会发现以下类有用:
-
ACE_RW_Process_Mutex
-
ACE_Write_Guard
和ACE_Read_Guard
-
ACE_Condition
http://www.codeproject.com/KB/threads/ReaderWriterLock.aspx
这是一个适合大多数任务的优秀和轻量级的实现。
Win32的多读者,单作者同步锁类由Glenn Slayde提供
C ++ 17支持std::shared_mutex
。 它在MSVC ++ 2015和2017中得到了支持。
你可以复制Sun的优秀的ReentrantReadWriteLock 。 它包括诸如可选的公平性,locking降级以及当然可重入等function。
是的,它是用Java编写的,但是即使你不知道任何Java,你也可以轻松地读取和转换成C ++。 我链接到的文档包含了这个实现的所有行为属性,所以你可以确保它做你想要的。
如果没有别的,这是一个指导。