我正在寻找一个很好的C ++读写器锁。我们有一个不常见的作家和许多常见读者的用例,并希望为此进行优化。我更喜欢跨平台的解决方案,但只有Windows可以接受。
答案 0 :(得分:33)
较新版本的boost::thread具有读/写锁(1.35.0及更高版本,显然以前的版本无法正常工作)。
他们的名称为shared_lock
,unique_lock
和upgrade_lock
,并在shared_mutex
上运作。
答案 1 :(得分:33)
使用标准预测试,预先构建的东西总是很好(例如,Boost作为建议的另一个答案),但这是一个不太难以自己构建的东西。这是从我的一个项目中抽出的一个愚蠢的小实现:
#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
,如果您宁愿相反,那么就可以修改pthread_rwlock_*
。
是的,这是C而不是C ++。翻译是留给读者的一项练习。
Greg Rogers指出POSIX标准确实指定了pthreads
。如果你没有pthreads
,这没有任何帮助,但它激起了我的记忆:Pthreads-w32应该有效!不要将此代码移植到非pthreads
供自己使用,而只需在Windows上使用Pthreads-w32,在其他地方使用本地{{1}}。
答案 2 :(得分:20)
您可以使用boost来创建读写锁:
#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
}
答案 3 :(得分:13)
无论您决定使用什么,都要将工作负载与简单锁定进行对比,因为当没有争用时,读/写锁定比简单互斥锁慢3-40倍。
答案 4 :(得分:9)
编辑:MSDN Magazine链接不再可用。 CodeProject的文章现在可以在https://www.codeproject.com/Articles/32685/Testing-reader-writer-locks上找到,并且很好地总结了它。我还找到了关于Compound Synchronisation Objects的新MSDN链接。
MSDN上有一个关于读写器锁的article,它提供了一些实现。它还介绍了Slim读/写锁,这是Vista引入的内核同步原语。还有CodeProject article关于比较不同的实现(包括MSDN文章的实现)。
答案 5 :(得分:4)
英特尔®线程构建模块还提供了几种rw_lock变体:
http://www.threadingbuildingblocks.org/
他们有一个spin_rw_mutex用于非常短的争用时间,而一个queueing_rw_mutex用于更长时间的争用。前者可用于特别敏感的性能代码。后者在性能上与Boost.Thread或直接使用pthreads提供的性能相当。但是要确定哪一个是您的访问模式的胜利。
答案 6 :(得分:4)
C ++ 17支持std::shared_mutex
。它在MSVC++ 2015和2017年支持。
答案 7 :(得分:3)
我可以推荐ACE library,它提供了多种锁定机制,并移植到各种平台。
根据问题的边界条件,您可能会发现以下类很有用:
ACE_RW_Process_Mutex
ACE_Write_Guard
和ACE_Read_Guard
ACE_Condition
答案 8 :(得分:3)
Boost.Thread自发布以来1.35.0已经支持读写器锁。关于这一点的好处是,实施是跨平台的,经过同行评审的,实际上是a reference implementation for the upcoming C++0x standard。
答案 9 :(得分:2)
http://www.codeproject.com/KB/threads/ReaderWriterLock.aspx
这是一个适合大多数任务的优秀且轻量级的实现。
答案 10 :(得分:2)
Glenn Slayde的Win32多读取器,单写器同步锁定类
答案 11 :(得分:0)
你可以复制Sun的优秀ReentrantReadWriteLock。它包括可选的公平性,锁定降级,当然还有可重入性等功能。
是的,它是用Java编写的,但即使你不懂任何Java,也可以轻松地将它读取并转换为C ++。我链接到的文档包含此实现的所有行为属性,因此您可以确保它执行您想要的操作。
如果不出意外,这是一个指南。