У меня есть многопоточное приложение, которое должно часто читать некоторые данные, и иногда эти данные обновляются. Прямо сейчас мьютекс сохраняет доступ к этим данным безопасным, но это дорого, потому что я хотел бы, чтобы несколько потоков могли читать одновременно, и блокировать их только тогда, когда требуется обновление (поток обновления может ждать завершения других потоков) ,
Я думаю, что это то, что boost::shared_mutex
нужно делать, но я не понимаю, как это использовать, и не нашел четкого примера.
Есть ли у кого-нибудь простой пример, который я мог бы использовать для начала?
c++
multithreading
boost
mutex
boost-thread
kevin42
источник
источник
Ответы:
Похоже, вы бы сделали что-то вроде этого:
источник
1800 ИНФОРМАЦИЯ более или менее верна, но есть несколько проблем, которые я хотел бы исправить.
Также обратите внимание: в отличие от shared_lock, только один поток может получить upgrade_lock за один раз, даже если он не обновлен (что, как мне показалось, было неудобно, когда я столкнулся с ним). Итак, если все ваши читатели - условные писатели, вам нужно найти другое решение.
источник
boost::unique_lock< boost::shared_mutex > lock(lock);
читатьboost::unique_lock< boost::shared_mutex > lock(
_access);
?Начиная с C ++ 17 (VS2015) вы можете использовать стандарт для блокировок чтения-записи:
Для более старой версии вы можете использовать boost с тем же синтаксисом:
источник
typedef boost::unique_lock< Lock > WriteLock; typedef boost::shared_lock< Lock > ReadLock;
.Просто чтобы добавить еще немного эмпирической информации, я исследовал всю проблему обновляемых блокировок и пример повышения shared_mutex (несколько чтений / одна запись)? - хороший ответ, добавляющий важную информацию о том, что только один поток может иметь upgrade_lock, даже если он не обновлен, что важно, поскольку это означает, что вы не можете перейти с общей блокировки на уникальную, не освободив сначала общую блокировку. (Это обсуждалось в другом месте, но самая интересная тема здесь http://thread.gmane.org/gmane.comp.lib.boost.devel/214394 )
Однако я обнаружил важное (недокументированное) различие между потоком, ожидающим обновления до блокировки (т.е. должен ждать, пока все читатели освободят разделяемую блокировку), и блокировкой писателя, ожидающей того же самого (например, unique_lock).
Поток, который ожидает unique_lock на shared_mutex, блокирует всех входящих читателей, они должны ждать запроса писателей. Это гарантирует, что читатели не умрут писателей голодом (однако я считаю, что писатели могут голодать читателей).
Поток, который ожидает обновления upgradeable_lock, позволяет другим потокам получить разделяемую блокировку, поэтому этот поток может испытывать нехватку ресурсов, если считыватели очень часты.
Это важный вопрос для рассмотрения и, вероятно, должен быть задокументирован.
источник
Terekhov algorithm
гарантирует1.
, что писатель не может морить читателей голодом. Смотрите это . Но2.
верно. Upgrade_lock не гарантирует справедливости. Смотрите это .Используйте семафор со счетчиком, равным количеству читателей. Пусть каждый читатель сделает один отсчет семафора для чтения, чтобы все они могли читать одновременно. Затем позвольте писателю взять ВСЕ счетчики семафоров перед записью. Это заставляет писатель ждать завершения всех чтений, а затем блокировать чтение во время записи.
источник
Отличный отклик Джима Морриса, я наткнулся на это, и мне потребовалось время, чтобы понять. Вот простой код, который показывает, что после отправки «запроса» на повышение unique_lock (версия 1.54) все запросы shared_lock блокируются. Это очень интересно, поскольку мне кажется, что выбор между unique_lock и upgradeable_lock позволяет нам, хотим ли мы иметь приоритет записи или нет.
Также (1) в сообщении Джима Морриса, похоже, противоречит этому: Boost shared_lock. Читать предпочитаете?
источник