Пример для повышения общего мьютекса (несколько чтений/одна запись)?


У меня есть многопоточное приложение, которое должно часто читать некоторые данные, и иногда эти данные обновляются. Прямо сейчас мьютекс сохраняет доступ к этим данным безопасным, но это дорого, потому что я хотел бы, чтобы несколько потоков могли читать одновременно и блокировать их только тогда, когда требуется обновление (поток обновления может ждать завершения других потоков).

Я думаю, что это boost::shared_mutex должен делать, но я не понимаю, как его использовать, и не нашел четкого образец.

есть ли у кого-нибудь простой пример, который я мог бы использовать для начала?

6 107

6 ответов:

похоже, вы бы сделали что-то вроде этого:

boost::shared_mutex _access;
void reader()
{
  // get shared access
  boost::shared_lock<boost::shared_mutex> lock(_access);

  // now we have shared access
}

void writer()
{
  // get upgradable access
  boost::upgrade_lock<boost::shared_mutex> lock(_access);

  // get exclusive access
  boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
  // now we have exclusive access
}

1800 информация более или менее правильная, но есть несколько вопросов, которые я хотел бы исправить.

boost::shared_mutex _access;
void reader()
{
  boost::shared_lock< boost::shared_mutex > lock(_access);
  // do work here, without anyone having exclusive access
}

void conditional_writer()
{
  boost::upgrade_lock< boost::shared_mutex > lock(_access);
  // do work here, without anyone having exclusive access

  if (something) {
    boost::upgrade_to_unique_lock< boost::shared_mutex > uniqueLock(lock);
    // do work here, but now you have exclusive access
  }

  // do more work here, without anyone having exclusive access
}

void unconditional_writer()
{
  boost::unique_lock< boost::shared_mutex > lock(_access);
  // do work here, with exclusive access
}

Также обратите внимание, что в отличие от shared_lock, только один поток может получить upgrade_lock за один раз, даже если он не обновлен (что я думал, было неудобно, когда я столкнулся с ним). Итак, если все ваши читатели-условные писатели, вам нужно найти другое решение.

вы можете использовать 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
}

просто чтобы добавить еще немного эмпирической информации, я исследовал всю проблему обновляемых замков, и пример для boost shared_mutex (несколько чтений/одна запись)? хороший ответ добавление важной информации о том, что только один поток может иметь upgrade_lock, даже если он не обновлен, что важно, поскольку это означает, что вы не можете перейти от общей блокировки к уникальной блокировке, не отпустив сначала общую блокировку. (Это обсуждалось в другом месте, но самое интересное нить здесь http://thread.gmane.org/gmane.comp.lib.boost.devel/214394)

однако я нашел важную (недокументированную) разницу между потоком, ожидающим обновления до блокировки (т. е. нужно ждать, пока все читатели освободят общую блокировку), и блокировкой записи, ожидающей того же (т. е. unique_lock).

  1. поток, который ждет unique_lock на shared_mutex блокирует любые новые читатели, они должны ждать писатели просят. Это гарантирует, что читатели не голодают писатели (однако я считаю, что писатели могут голодать читателей).

  2. поток, ожидающий обновления upgradeablock, позволяет другим потокам получить общую блокировку, поэтому этот поток может быть голоден, если читатели очень часто.

Это важный вопрос для рассмотрения и, вероятно, должен быть задокументирован.

используйте семафор с числом, равным числу считывателей. Пусть каждый читатель возьмет один счетчик семафора, чтобы читать, таким образом, они все могут читать одновременно. Затем пусть писатель возьмет все семафорные счетчики до написания. Это заставляет писателя ждать завершения всех операций чтения, а затем блокировать операции чтения во время записи.