[C++] Пример для boost shared_mutex (многократное чтение / запись)?


Answers

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

Question

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

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

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




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

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

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

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

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




Великий ответ Джима Морриса, я наткнулся на это, и мне потребовалось некоторое время, чтобы понять. Вот простой код, который показывает, что после отправки «запроса» для boost_lock boost (версия 1.54) блокируются все запросы shared_lock. Это очень интересно, поскольку мне кажется, что выбор между unique_lock и upgradeable_lock позволяет, если мы хотим, чтобы приоритет записи был приоритет или нет приоритета.

Также (1) в сообщении Джима Морриса, похоже, противоречит этому: Boost shared_lock. Читайте предпочитаете?

#include <iostream>
#include <boost/thread.hpp>

using namespace std;

typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock > UniqueLock;
typedef boost::shared_lock< Lock > SharedLock;

Lock tempLock;

void main2() {
    cout << "10" << endl;
    UniqueLock lock2(tempLock); // (2) queue for a unique lock
    cout << "11" << endl;
    boost::this_thread::sleep(boost::posix_time::seconds(1));
    lock2.unlock();
}

void main() {
    cout << "1" << endl;
    SharedLock lock1(tempLock); // (1) aquire a shared lock
    cout << "2" << endl;
    boost::thread tempThread(main2);
    cout << "3" << endl;
    boost::this_thread::sleep(boost::posix_time::seconds(3));
    cout << "4" << endl;
    SharedLock lock3(tempLock); // (3) try getting antoher shared lock, deadlock here
    cout << "5" << endl;
    lock1.unlock();
    lock3.unlock();
}