STL-вектор и безопасность потоков
Скажем, у меня есть вектор из N элементов, но до n элементов этого вектора имеют значимые данные. Один поток обновления обновляет n-й или n + 1-й элемент (тогда устанавливает n = n + 1), также проверяет, слишком ли n близко к N и при необходимости вызывает vector:: resize (N + M). После обновления поток вызывает несколько дочерних потоков для чтения до n-го данных и выполняет некоторые вычисления.
Гарантируется, что дочерние потоки никогда не изменяют или не удаляют данные (на самом деле ни один из данных не удаляется, что когда-либо), а updater вызывает детей сразу после завершения обновления.
До сих пор проблема не возникала, но я хочу спросить, может ли возникнуть проблема при перераспределении вектора в более крупный блок памяти, если есть некоторые дочерние рабочие потоки, оставшиеся от предыдущего обновления.
Или безопасно использовать вектор, поскольку он не является потокобезопасным, в таком многопоточном случае?
EDIT:
Поскольку только вставка происходит, когда программа обновления вызывает вектор:: resize (N + M, 0), есть ли какие-либо возможные решения моей проблемы? Из-за большой производительности STL-вектора я не желаю заменять его блокируемым вектором или в этом случае есть ли какие-либо исполняемые, известные и незакрепленные векторы?
Ответы
Ответ 1
Я хочу спросить, может ли возникнуть проблема при перераспределении вектора в более крупный блок памяти, если есть некоторые дочерние рабочие потоки, оставшиеся от предыдущего обновления.
Да, это было бы очень плохо.
Если вы используете контейнер из нескольких потоков, и хотя бы один поток может выполнять некоторые действия, которые могут изменять состояние контейнера, доступ к контейнеру должен быть синхронизирован.
В случае std::vector
все, что меняет свой размер (в частности, вставки и стирания), меняет свое состояние, даже если перераспределение не требуется (для любой вставки или стирания требуются обновленные данные о внутренней сортировке std::vector
).
Одним из решений вашей проблемы было бы обеспечить динамическое распределение производителем std::vector
и использовать std::shared_ptr<std::vector<T> >
для его владения и предоставить этому std::shared_ptr
каждому из потребителей.
Когда продюсеру нужно добавить больше данных, он может динамически выделять новый std::vector
с новым, большим размером и копиями элементов из старого std::vector
. Затем, когда вы выделяете новых потребителей или обновляете потребителей новыми данными, вам просто нужно дать им std::shared_ptr
для нового std::vector
.
Ответ 2
Как ваши работники решают работать над потоками данных? Есть ли какая-либо сигнализация между работниками и продюсером? Если нет, то определенно возникает проблема, когда производитель может заставить вектор двигаться, пока он еще работает. Хотя это можно было бы тривиально зафиксировать, перейдя к std::deque
вместо этого. (Обратите внимание, что std::deque
делает недействительными итераторы на push_back
, но ссылки на элементы не затрагиваются).
Ответ 3
Я создал свой собственный GrowVector. Это работает для меня, и это очень быстро.
Ссылка: QList, QVector или std::vector многопоточное использование