73

我正在寻找一个好的 C++ 读/写锁。我们有一个不常写者和许多常读者的用例,并希望对此进行优化。最好我想要一个跨平台的解决方案,但是只有一个 Windows 是可以接受的。

4

12 回答 12

44

从 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;
于 2011-06-23T07:15:17.423 回答
37

较新版本的boost::thread具有读/写锁(1.35.0 及更高版本,显然以前的版本无法正常工作)。

它们具有名称shared_lock,unique_lockupgrade_lock, 对 a 进行操作shared_mutex

于 2008-10-28T18:36:58.290 回答
35

使用标准的预测试、预构建的东西总是好的(例如,另一个答案建议的 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在其他任何地方使用原生代码。

于 2008-10-28T18:46:10.487 回答
16

无论您决定使用什么,都将您的工作负载与简单锁进行基准测试,因为当没有争用时,读/写锁往往比简单互斥锁慢 3-40 倍。

这里有一些参考

于 2008-10-28T19:23:32.380 回答
10

编辑:MSDN 杂志链接不再可用。CodeProject 文章现在可以在https://www.codeproject.com/Articles/32685/Testing-reader-writer-locks上找到,并且总结得很好。我还发现了一个关于Compound Synchronization Objects的新 MSDN 链接。

MSDN 上有一篇关于读写锁的文章,介绍了它们的一些实现。它还引入了 Slim 读取器/写入器锁,这是一种随 Vista 引入的内核同步原语。还有一篇关于比较不同实现的CodeProject 文章(包括 MSDN 文章的那些)。

于 2009-01-29T07:29:06.517 回答
8

C++17 支持std::shared_mutex. 它在MSVC++ 2015和 2017 中受支持。

于 2017-05-28T14:54:56.097 回答
4

英特尔线程构建模块还提供了几个 rw_lock 变体:

http://www.threadingbuildingblocks.org/

他们有一个 spin_rw_mutex 用于非常短的争用时间和一个 queueing_rw_mutex 用于较长时间的争用。前者可用于对性能特别敏感的代码。后者在性能上与 Boost.Thread 或直接使用 pthreads 提供的性能更具可比性。但是配置文件以确保哪个是您的访问模式的胜利。

于 2008-11-05T19:04:10.117 回答
3

我可以推荐ACE 库,它提供了多种锁定机制并被移植到各种平台。

根据问题的边界条件,您可能会发现以下类很有用:

  • ACE_RW_Process_Mutex
  • ACE_Write_GuardACE_Read_Guard
  • ACE_Condition
于 2008-10-28T19:08:06.763 回答
3

Boost.Thread自 1.35.0 版以来已经支持读写锁。这样做的好处是该实现非常跨平台,经过同行评审,实际上是即将到来的 C++0x 标准的参考实现

于 2008-10-28T19:10:28.597 回答
2

http://www.codeproject.com/KB/threads/ReaderWriterLock.aspx

这是一个适用于大多数任务的良好且轻量级的实现。

于 2011-03-08T09:58:27.590 回答
2

用于 Win32 的多读取器、单写入器同步锁类,作者 Glenn Slayde

http://www.glennslayden.com/code/win32/reader-writer-lock

于 2011-05-31T19:31:29.783 回答
0

您可以复制 Sun 出色的ReentrantReadWriteLock。它包括可选的公平性、锁定降级,当然还有可重入性等功能。

是的,它是用 Java 编写的,但即使您不了解任何 Java,您也可以轻松阅读并将其转换为 C++。我链接到的文档包含此实现的所有行为属性,因此您可以确保它符合您的要求。

如果没有别的,它是一个指南。

于 2008-10-28T18:31:32.483 回答