2010-12-03 5 views
11

Предположим, что у меня есть вектор из N элементов, но до n элементов этого вектора имеют значимые данные. Один поток обновления обновляет n-й или n + 1-й элемент (тогда устанавливает n = n + 1), также проверяет, слишком ли n близко к N и при необходимости вызывает vector :: resize (N + M). После обновления поток вызывает несколько дочерних потоков для чтения до n-го данных и выполняет некоторые вычисления.STL вектор и безопасность потоков

Гарантируется, что дочерние потоки никогда не изменяют или не удаляют данные (фактически данные не удаляются, что когда-либо), а updater вызывает детей сразу после завершения обновления.

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

EDIT: Поскольку только вставка происходит, когда программа обновления вызывает вектор :: resize (N + M, 0), есть ли какие-либо возможные решения моей проблемы? Из-за большой производительности STL-вектора я не желаю заменять его блокируемым вектором или в этом случае есть ли какие-либо исполняемые, известные и незакрепленные векторы?

ответ

19

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

Да, это было бы очень плохо.

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

В случае std::vector, все, что изменяет свой размер (в частности, вставка и подчистка) изменять свое состояние, даже если перераспределение не требуется (любая вставка или стирание требует внутренних данных размера бухгалтерских std::vector «S быть обновлены) ,


Одно решение вашей проблемы будет иметь производитель динамически выделять std::vector и использовать std::shared_ptr<std::vector<T> > владеть ею и дать этот std::shared_ptr каждому из потребителей.

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

+0

@James McNellis: Да. Это хороший совет.Я могу сделать перераспределение себя. Фактически векторы обернуты внутри класса, который содержит указатель на вектор. Это не shared_ptr, но я могу легко построить новый более крупный вектор, скопировать элементы из старого, удалить его. Итак, каков самый быстрый способ скопировать большой блок памяти. CopyMemory()? – 2010-12-03 15:53:26

+1

Не проще было бы использовать `std :: deque` вместо вектора? Это позволяет избежать перераспределения полностью, при этом обеспечивая производительность почти наравне с вектором. – jalf 2010-12-03 16:30:36

1

Как ваши работники решают работать над безопасностью потоков данных? Есть ли какая-либо сигнализация между работниками и продюсером? Если нет, то определенно возникает проблема, когда производитель может заставить вектор двигаться, пока он еще работает. Хотя это можно было бы тривиально зафиксировать, перейдя на std::deque (обратите внимание, что std::deque делает недействительными итераторы на push_back, но ссылки на элементы не затрагиваются).

Смежные вопросы