【发布时间】:2010-09-19 15:33:39
【问题描述】:
我正在寻找一个好的 C++ 读/写锁。我们有一个不常写者和许多常读者的用例,并希望对此进行优化。最好我想要一个跨平台的解决方案,但是只有一个 Windows 是可以接受的。
【问题讨论】:
标签: c++ multithreading locking
我正在寻找一个好的 C++ 读/写锁。我们有一个不常写者和许多常读者的用例,并希望对此进行优化。最好我想要一个跨平台的解决方案,但是只有一个 Windows 是可以接受的。
【问题讨论】:
标签: c++ multithreading locking
从 C++ 17 (VS2015) 开始可以使用标准:
#include <shared_mutex>
typedef std::shared_mutex Lock;
typedef std::unique_lock< Lock > WriteLock;
typedef std::shared_lock< Lock > ReadLock;
Lock myLock;
void ReadFunction()
{
ReadLock r_lock(myLock);
//Do reader stuff
}
void WriteFunction()
{
WriteLock w_lock(myLock);
//Do writer stuff
}
对于较旧的编译器版本和标准,您可以使用 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;
【讨论】:
boost::thread 的较新版本具有读/写锁(1.35.0 及更高版本,显然以前的版本无法正常工作)。
它们的名称为 shared_lock、unique_lock 和 upgrade_lock,并在 shared_mutex 上运行。
【讨论】:
shared_timed_mutex 和匹配的 shared_lock。
使用标准的预测试、预构建的东西总是好的(例如,另一个答案建议的 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。
是的,这是 C 而不是 C++。翻译是留给读者的练习。
Greg Rogers 指出 POSIX 标准确实指定了pthread_rwlock_*。如果您没有pthreads,这将无济于事,但它让我想起:Pthreads-w32 应该有效!不要将此代码移植到非pthreads 以供您自己使用,只需在Windows 上使用Pthreads-w32,在其他任何地方使用本机pthreads。
【讨论】:
无论您决定使用什么,都将您的工作负载与简单锁进行基准比较,因为在没有争用的情况下,读/写锁往往比简单互斥锁慢 3-40 倍。
【讨论】:
编辑:MSDN 杂志链接不再可用。 CodeProject 文章现在可以在https://www.codeproject.com/Articles/32685/Testing-reader-writer-locks 上找到,并且总结得很好。我还发现了一个关于 Compound Synchronisation Objects 的新 MSDN 链接。
在 MSDN 上有一个关于读写锁的article,其中介绍了它们的一些实现。它还引入了 Slim 读取器/写入器锁,这是一种随 Vista 引入的内核同步原语。还有一个 CodeProject article 用于比较不同的实现(包括 MSDN 文章的那些)。
【讨论】:
C++17 支持 std::shared_mutex 。它在 MSVC++ 2015 和 2017 中受支持。
【讨论】:
shared_timed_mutex 和匹配的 shared_lock。
英特尔线程构建模块还提供了几个 rw_lock 变体:
http://www.threadingbuildingblocks.org/
它们有一个 spin_rw_mutex 用于非常短的争用时间和一个 queueing_rw_mutex 用于较长时间的争用。前者可用于对性能特别敏感的代码。后者在性能上与 Boost.Thread 或直接使用 pthreads 提供的性能更具可比性。但是配置文件以确保哪个是您的访问模式的胜利。
【讨论】:
Boost.Thread 自 1.35.0 版以来已经支持读写锁。这样做的好处是该实现非常跨平台,经过同行评审,实际上是a reference implementation for the upcoming C++0x standard。
【讨论】:
我可以推荐ACE library,它提供了多种锁定机制并被移植到各种平台。
根据问题的边界条件,您可能会发现以下类很有用:
ACE_RW_Process_MutexACE_Write_Guard 和 ACE_Read_Guard
ACE_Conditionhttp://www.codeproject.com/KB/threads/ReaderWriterLock.aspx
这是一个适合大多数任务的优秀且轻量级的实现。
【讨论】:
Glenn Slayde 的 Win32 多读单写同步锁类
【讨论】:
您可以复制 Sun 出色的 ReentrantReadWriteLock。它包括可选的公平性、锁定降级,当然还有重入等功能。
是的,它是用 Java 编写的,但即使您不懂任何 Java,您也可以轻松阅读并将其转换为 C++。我链接到的文档包含此实现的所有行为属性,因此您可以确保它符合您的要求。
如果没有别的,那就是指南。
【讨论】:
finally,因此在存在异常的情况下,直接从 Java 转换为 C++ 是个坏主意。