Вы должны понимать, что потокобезопасность гарантирует стандарт C ++ (и реализации C ++ 2003 для возможно параллельных систем).Стандартные контейнеры являются поточно-ориентированными в следующем смысле:
- Можно иметь несколько параллельных потоков, читающих один и тот же контейнер.
- Если существует один поток, модифицирующий контейнерне должно быть одновременных потоков, читающих или пишущих один и тот же контейнер.
- Различные контейнеры не зависят друг от друга.
Многие люди неправильно понимают безопасность потоков в контейнере, что означает наложение этих правилреализация контейнера: они не!Вы несете ответственность за соблюдение этих правил.
Причина, по которой контейнеры не налагаются и не могут быть навязаны, заключается в том, что у них нет подходящего для этого интерфейса.Рассмотрим, например, следующий тривиальный код:
if (!c.empty() {
auto value = c.back();
// do something with the read value
}
Контейнер может контролировать доступ к вызовам на empty()
и back()
.Тем не менее, между этими вызовами необходимо обязательно освободить любые средства синхронизации, т. Е. К тому моменту, когда поток попытается прочитать c.back()
, контейнер может снова оказаться пустым!Существуют два основных способа решения этой проблемы:
- Необходимо использовать внешнюю блокировку, если существует вероятность того, что параллельный поток может изменять контейнер для охвата всего диапазона обращений, которые взаимозависимы внекоторая форма.
- Вы изменяете интерфейс контейнеров, чтобы они стали мониторами .Однако интерфейс контейнера не подходит для изменения в этом направлении, потому что мониторы по существу поддерживают только интерфейсы типа «запусти и забудь».
Обе стратегии имеют свои преимущества и стандартные контейнеры библиотекиявно поддерживают первый стиль, то есть они требуют внешней блокировки при использовании одновременно с потенциалом, по крайней мере, одного потока, модифицирующего контейнер.Они не требуют какой-либо блокировки (ни внутренней, ни внешней), если вначале используется только один поток.Это фактически сценарий, для которого они были разработаны.Предоставленные им гарантии безопасности потока гарантируют отсутствие используемых внутренних средств, которые не являются потокобезопасными, например, один объект-итератор для каждого объекта или средство выделения памяти, совместно используемое несколькими потоками, не будучи поточно-безопасным, и т. Д..
Чтобы ответить на исходный вопрос: да, вам нужно использовать внешнюю синхронизацию, например, в форме блокировок мьютекса, если вы изменяете контейнер в одном потоке и читаете его в другом потоке.