Записи чтения/записи в С++

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

Ответ 1

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

У них есть имена shared_lock, unique_lock и upgrade_lock и работать с shared_mutex.

Ответ 2

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

Изменить

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

Ответ 3

Начиная с 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;

Ответ 4

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

Вот некоторая ссылка

Ответ 5

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

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

Ответ 7

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

http://www.threadingbuildingblocks.org/

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

Ответ 8

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

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

  • ACE_RW_Process_Mutex
  • ACE_Write_Guard и ACE_Read_Guard
  • ACE_Condition

Ответ 12

Вы можете скопировать Sun отлично ReentrantReadWriteLock. Он включает в себя такие функции, как необязательная справедливость, понижение рейтинга и, конечно, повторное размещение.

Да, это в Java, но вы можете легко прочитать и перенести его на С++, даже если вы не знаете Java. Документация, с которой я связан, содержит все поведенческие свойства этой реализации, поэтому вы можете убедиться, что она делает то, что вы хотите.

Если ничего другого, это руководство.