Безопасен ли поток std :: vector или boost :: vector? - PullRequest
34 голосов
/ 28 января 2012

У меня есть несколько потоков, одновременно вызывающих push_back() для общего объекта std::vector. std::vector поток безопасен? Или мне нужно самому внедрить механизм, чтобы сделать его потокобезопасным?
Я хочу избегать дополнительной "блокировки и освобождения" работы, потому что я пользователь библиотеки, а не разработчик библиотеки. Я надеюсь найти существующие поточно-ориентированные решения для вектора. Как насчет boost::vector, который был недавно представлен с boost 1.48.0 и далее. Это потокобезопасно?

Ответы [ 3 ]

52 голосов
/ 28 января 2012

Стандарт C ++ дает определенные гарантии многопоточности для всех классов в стандартной библиотеке C ++. Эти гарантии могут быть не такими, как вы ожидаете, но для всех стандартных классов библиотеки C ++ сделаны определенные гарантии безопасности потоков. Убедитесь, что вы прочитали предоставленные гарантии, поскольку гарантии потоков в стандартных контейнерах C ++ обычно не совпадают с желаемыми. Для некоторых классов разные, как правило, более строгие гарантии, и ответ ниже конкретно относится к контейнерам. Контейнеры по существу имеют следующие гарантии безопасности потока:

  1. может быть несколько одновременных считывателей одного контейнера
  2. если есть один писатель, больше не будет писателей и читателей

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

Чтобы соответствовать требованиям, которые дают вышеупомянутые гарантии, вам, вероятно, придется использовать некоторую форму внешней блокировки для одновременно доступных контейнеров. Я не знаю о буст-контейнерах, но если они имеют интерфейс, аналогичный интерфейсу стандартных контейнеров, я подозреваю, что они имеют точно такие же гарантии.

Гарантии и требования приведены в пункте 17.6.4.10 [res.on.objects]:

Поведение программы не определено, если вызовы стандартных библиотечных функций из разных потоков могут привести к гонке данных. Условия, при которых это может произойти, указаны в 17.6.5.9. [Примечание: изменение объекта стандартного типа библиотеки, который используется совместно между потоками, может привести к неопределенному поведению, если только объекты этого типа явно не определены как разделяемые без гонок данных или пользователь не предоставит механизм блокировки. -endnote]

... и 17.6.5.9 [res.on.data.races]. Этот раздел по существу детализирует более неформальное описание в статье.

27 голосов
/ 28 января 2012

У меня есть несколько потоков, одновременно вызывающих push_back () для общего объекта std :: vector.Безопасен ли поток std :: vector?

Это небезопасно .

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

Да.

Я хочу избежать дополнительной «блокировки и освобождения» работы, потому что я пользователь библиотеки, а не разработчик библиотеки.Я надеюсь найти существующие поточно-ориентированные решения для вектора.

Что ж, интерфейс вектора не оптимален для одновременного использования.Хорошо, если у клиента есть доступ к блокировке, но для интерфейса для абстрактной блокировки для каждой операции - нет.На самом деле, векторный интерфейс не может гарантировать безопасность потоков без внешней блокировки (при условии, что вам нужны операции, которые также изменяются).

Как насчет boost :: vector, который был недавно представлен с boost 1.48.0 и далее.Это потокобезопасно?

Состояние документов:

//! boost::container::vector is similar to std::vector but it's compatible
//! with shared memory and memory mapped files.
9 голосов
/ 29 января 2012

У меня есть несколько потоков, одновременно вызывающих push_back () для общего объекта std :: vector.... Я надеюсь найти существующие поточно-ориентированные решения для вектора.

Взгляните на concurrent_vector в Intel TBB .Строго говоря, он сильно отличается от std::vector внутренне и не полностью совместим с API, но все же может подойти.Вы можете найти некоторые детали его дизайна и функциональности в блогах разработчиков TBB .

...