Является ли С++ std:: set потокобезопасным? - программирование
Подтвердить что ты не робот

Является ли С++ std:: set потокобезопасным?

У меня вопрос о безопасности потока std:: set.

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

Но рассмотрим следующий сценарий:

  • thread 'A' выполняет итерацию по набору shared_ptr <Type>
  • поток 'B' иногда добавляет элементы к этому набору.

Я испытал segfaults по мере запуска программы, и я не уверен, почему это происходит. Отсутствует ли проблема безопасности потока?

4b9b3361

Ответ 1

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

Например, посмотрите здесь: текст ссылки

Поскольку set - это контейнерный класс, MSDN имеет следующие значения для безопасности потоков контейнеров.

Один объект является потокобезопасным для чтения из нескольких потоков. Например, при заданном объекте A безопасно читать A из потока 1 и из потока 2 одновременно.

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

Безопасно читать и записывать один экземпляр типа, даже если другой поток читает или записывает в другой экземпляр того же типа. Например, для заданных объектов A и B того же типа, безопасно, если A записывается в потоке 1, а B читается в потоке 2.

Ответ 2

Документация STL-Dinkumware содержит следующий абзац об этой теме. Его вероятно (как указано в тексте), действительный для большинства реализаций.

Для объектов контейнера, определенных в стандартная библиотека С++, такая как STL Контейнеры и объекты шаблона class basic_string, это осуществление следует широко принятые практики, изложенные для SGI STL:

Несколько потоков могут безопасно читать один и тот же объект-контейнер. (Есть nunprotected измененные подобъекты внутри контейнерный объект.)

Два потока могут безопасно манипулировать различными контейнерными объектами одного типа. (Нет незащищенные общие статические объекты в пределах типа контейнера.)

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

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

Ответ 3

Ни один из контейнеров STL не является потокобезопасным, поэтому std::set в частности isnt.

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

D'ах! В разделе 23.1.2.8 указано, что вставка не делает недействительными итераторы.

Ответ 4

Простое объяснение: если поток A перемещает итераторы через контейнер, он смотрит на внутренности контейнера. Если поток B изменяет контейнер (даже операция, которая не делает недействительным итератор, который имеет A), поток A может столкнуться с проблемами, потому что B обманывает внутренности контейнера, возможно, имея их в (временно) недействительном состоянии. Это приводит к сбоям в потоке A.

Проблема НЕ является самими итераторами. Это когда им нужны структуры данных контейнера, чтобы найти положение, в котором вы попадаете.

Просто как это.

Ответ 5

Да. Один из способов справиться с этой ситуацией состоит в том, чтобы каждый поток блокировал общий мьютекс перед доступом к одному и тому же заданному объекту. Убедитесь, что вы используете методы RAII для блокировки и разблокировки мьютекса.

Ответ 6

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