2012-01-28 1 views
29

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

+0

Это должно быть дуплекс. Но нет, ни один из стандартных контейнеров не является потокобезопасным. – smparkes

+0

См. Также: http://stackoverflow.com/questions/1999122/how-to-define-threadsafe – ergosys

+0

Не совсем обман, но связанные: http://stackoverflow.com/questions/1099513/threadsafe-vector-class- for-c – ergosys

ответ

44

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

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

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

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

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

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

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

+0

Это называется reentrancy :) – vines

+2

Это было бы [reentrancy] (http://en.wikipedia.org/wiki/Reentrancy_%28computing%29), если бы оно было только функцией. Однако есть объекты, которые гарантированно не могут быть изменены с помощью операций чтения. Кроме того, повторное подключение относится к функции рекурсивного вызова в однопоточных программах. –

+0

«Читатель» и «Писатель», вы говорите о структуре контейнера, а не записываете в объекты внутри, правильно? Например, запись в 3 разных элемента вектора и чтение из четвертой из еще десяти потоков будет разрешаться одновременно, пока никто не вставляет или не удаляет элементы. Правила правильности итератора здесь актуальны. –

25

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

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

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

Да.

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

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

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

Документы состояние:

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

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

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