Подтвердить что ты не робот

Является ли std::vector или boost:: vector thread безопасным?

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

Ответ 2

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

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

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

Да.

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

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

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

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

//! boost::container::vector is similar to std::vector but it compatible
//! with shared memory and memory mapped files.

Ответ 3

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

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

Ответ 4

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