繁体   English   中英

C++ 中的读/写锁

[英]Reader/Writer Locks in C++

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

从 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_lockunique_lockupgrade_lock并在shared_mutex上运行。

使用标准的预测试、预构建的东西总是好的(例如,另一个答案建议的 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 Synchronization Objects的新 MSDN 链接。

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

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

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

http://www.threadingbuildingblocks.org/

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

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

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

  • ACE_RW_Process_Mutex
  • ACE_Write_GuardACE_Read_Guard
  • ACE_Condition

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

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

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

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

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

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

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

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

#include <shared_mutex>

class Foo {
 public:
  void Write() {
    std::unique_lock lock{mutex_};
    // ... 
  }

  void Read() {
    std::shared_lock lock{mutex_};
    // ... 
  }

 private:
  std::shared_mutex mutex_;
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM