Блокировка чтения / записи в C ++ - PullRequest
62 голосов
/ 28 октября 2008

Я ищу хорошую блокировку чтения / записи в C ++. У нас есть сценарий использования одного нечастого автора и многих постоянных читателей, и мы хотели бы оптимизировать его. Предпочтительно, я бы хотел кроссплатформенное решение, однако Windows только один будет приемлемым.

Ответы [ 12 ]

33 голосов
/ 28 октября 2008

Использование стандартных предварительно протестированных, предварительно собранных вещей всегда хорошо (например, 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 ++. Перевод - это упражнение, оставленное читателю.

Редактировать

Грег Роджерс указал, что стандарт POSIX указывает pthread_rwlock_*. Это не поможет, если у вас нет pthreads, но это заставило меня вспомнить: Pthreads-w32 должно работать! Вместо того, чтобы переносить этот код на non-pthreads для собственного использования, просто используйте Pthreads-w32 в Windows и родной pthreads везде.

33 голосов
/ 28 октября 2008

Более новые версии boost :: thread имеют блокировки чтения / записи (1.35.0 и более поздние, очевидно, предыдущие версии работали некорректно).

Они имеют имена shared_lock, unique_lock и upgrade_lock и работают на shared_mutex .

20 голосов
/ 23 июня 2011

Вы можете использовать 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
}
13 голосов
/ 28 октября 2008

Что бы вы ни решили использовать, сравните свою рабочую нагрузку с простыми блокировками, поскольку блокировки чтения / записи, как правило, в 3-40 раз медленнее, чем простой мьютекс, когда нет конфликтов.

Вот справка

9 голосов
/ 29 января 2009

Редактировать: ссылка на журнал MSDN больше не доступна. Статья CodeProject теперь доступна на https://www.codeproject.com/Articles/32685/Testing-reader-writer-locks и прекрасно ее подводит. Также я нашел новую ссылку MSDN о объектах сложной синхронизации .

Существует статья о блокировках чтения-записи на MSDN, в которой представлены некоторые их реализации. Он также представляет блокировку Slim Reader / Writer, примитив синхронизации ядра, представленный в Vista. Также есть статья CodeProject о сравнении различных реализаций (включая статьи MSDN).

4 голосов
/ 28 мая 2017

C ++ 17 поддерживает std::shared_mutex. Поддерживается в MSVC ++ 2015 и 2017.

4 голосов
/ 05 ноября 2008

Intel Thread Building Blocks также предоставляет несколько вариантов rw_lock:

http://www.threadingbuildingblocks.org/

У них есть spin_rw_mutex для очень коротких периодов конкуренции и queueing_rw_mutex для более длительных периодов конкуренции. Первый может быть использован в особенно чувствительном к производительности коде. Последний более сопоставим по производительности с тем, что предоставляется Boost.Thread или напрямую с помощью pthreads. Но профиль, чтобы убедиться, какой из них является выигрышным для ваших шаблонов доступа.

3 голосов
/ 28 октября 2008

Boost.Thread с версии 1.35.0 уже поддерживает блокировки чтения-записи. Хорошая вещь об этом состоит в том, что реализация является в значительной степени кроссплатформенной, рецензируемой и фактически является эталонной реализацией для будущего стандарта C ++ 0x .

3 голосов
/ 28 октября 2008

Я могу порекомендовать библиотеку ACE , которая предоставляет множество механизмов блокировки и портирована на различные платформы.

В зависимости от граничных условий вашей задачи вам могут пригодиться следующие классы:

  • ACE_RW_Process_Mutex
  • ACE_Write_Guard и ACE_Read_Guard
  • ACE_Condition
2 голосов
/ 31 мая 2011

Класс блокировки синхронизации с несколькими устройствами чтения и записи для Win32 от Glenn Slayde

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

...