Skip to content

C++11 read-write lock implementation

C++11标准库并没有提供read-write lock ,那如何来实现呢?

算法

当可以读的时候,需要通知等待的reader;当不能读的时候,需要等待;

当可以写的时候,需要通知等待的write;当不能写的时候,需要等待;

因此,它需要使用两个condition variable;因此它的实现,非常类似于spdlog 中的 MPMC blocking queue;

Implementation

stackoverflow How would you implement your own reader/writer lock in C++11?

A

NOTE: 这个回答给出了分析过程,非常好;

read_lock() {
  mutex.lock();
  while (writer)
    unlocked.wait(mutex);
  readers++;
  mutex.unlock();
}

read_unlock() {
  mutex.lock();
  readers--;
  if (readers == 0)
    unlocked.signal_all();
  mutex.unlock();
}

write_lock() {
  mutex.lock();
  while (writer || (readers > 0))
    unlocked.wait(mutex);
  writer = true;
  mutex.unlock();
}

write_unlock() {
  mutex.lock();
  writer = false;
  unlocked.signal_all();
  mutex.unlock();
}

stackoverflow Reader/Writer Locks in C++

A

Newer versions of boost::thread have read/write locks (1.35.0 and later, apparently the previous versions did not work correctly).

A

NOTE: 下面给出的实现是非常典型的使用两个condition variable的实现;

Using standard pre-tested, pre-built stuff is always good (for example, Boost as another answer suggested), but this is something that's not too hard to build yourself. Here's a dumb little implementation pulled out from a project of mine:

#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 not really being Windows-native, but the general idea is here. This implementation is slightly biased towards writers (a horde of writers can starve readers indefinitely); just modify writer_unlock if you'd rather the balance be the other way around.

Yes, this is C and not C++. Translation is an exercise left to the reader.

Edit

Greg Rogers pointed out that the POSIX standard does specify pthread_rwlock_*. This doesn't help if you don't have pthreads, but it stirred my mind into remembering: Pthreads-w32 should work! Instead of porting this code to non-pthreads for your own use, just use Pthreads-w32 on Windows, and native pthreads everywhere else.

stackexchange Simple rwlock implementation in c++11

For answering this question of stackoverflow I have written the code https://stackoverflow.com/questions/12033188/how-would-you-implement-your-own-reader-writer-lock-in-c11

Can someone review it - so that I can understand the possible problems in the code.

NOTE: 下面给出的实现是非常典型的使用两个condition variable的实现;

#include <condition_variable>
#include <iostream>
#include <shared_mutex>
#include <thread>
#include <unistd.h>
#define NR_THREADS 10
#include <mutex>

class MySharedLock {
 public:
  void read_lock() {
    std::unique_lock<std::mutex> lk(rw_mutex);
    std::cout << "\nReader Lock Writers are  " << writers << std::flush;
    if (writers != 0) {
      rw_cv.wait(lk, [this]() { return (this->writers == 0); });
    }
    readers++;
    lk.unlock();
  }

  void write_lock() {
    std::unique_lock<std::mutex> lk(rw_mutex);

    std::cout << "\nWriter Lock Writers are  " << writers << " Readers are "
              << readers << std::flush;
    if (readers == 0 && writers == 0) {
      std::cout << "\nWriter Lock Writers are  " << writers << std::flush;
    } else {
      rw_cv.wait(
          lk, [this]() { return (this->writers == 0 && this->readers == 0); });
    }
    writers++;
    lk.unlock();

  }

  void write_unlock() {
    std::lock_guard<std::mutex> lk(rw_mutex);
    writers--;
    rw_cv.notify_all();
  }

  void read_unlock() {
    std::lock_guard<std::mutex> lk(rw_mutex);
    if (readers == 1) {  // I am the last one.
      rw_cv.notify_all();
    }
    readers--;
  }

  explicit MySharedLock() {}

 private:
  std::mutex rw_mutex;
  std::condition_variable rw_cv;
  uintmax_t readers = {0}, writers = {0};
};

stackoverflow C++11 equivalent to boost shared_mutex

A

I tried but failed to get shared_mutex into C++11. It has been proposed for a future standard. The proposal is here.

Edit: A revised version (N3659) was accepted for C++14.

Here is an implementation:

http://howardhinnant.github.io/shared_mutex

http://howardhinnant.github.io/shared_mutex.cpp

stackoverflow A RW lock for c++11 threads [duplicate]

preshing/cpp11-on-multicore/common/rwlock.h

NOTE: 算法都是相同的,只是它使用的了更加成熟的写法、实现,因此,推荐使用它;

在工程parallel-computing中,收录了这个实现;