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

Могу ли я создать потокобезопасный std:: atomic <vector <int>>?

У меня есть функция, которая должна выполняться n=1000 раз. Эта функция выполняет моделирование методом Монте-Карло и возвращает результат int. Я хотел бы запустить nthreads=4 параллельно. Всякий раз, когда нить заканчивает один цикл, он должен поместить результат в std::vector<int>. Таким образом, после 1000 циклов у меня есть вектор 1000 int, который может быть проверен статистикой.

Так как a std::vector не является потокобезопасным, я думал о std::mutex (который, несомненно, сработает).

Но мне интересно, могу ли я объявить вектор атомарным и, таким образом, обойти мьютексы? Возможно ли иметь std::atomic<std::vector<int>>? И могу ли я использовать push_back и т.д. На нем?

4b9b3361

Ответ 1

Вам не нужно. Все в порядке, чтобы получить доступ к ja std::vector из нескольких потоков, если

  • вы читаете объекты
  • вы пишете на разные объекты

Поэтому просто убедитесь, что вы создаете вектор размера n=1000 и в зависимости от вашего номера потока (от 1 до 4) вы назначаете в свои потоки элементы 0-249, 250-499 и т.д.

Итак, каждый из ваших потоков вычисляет элементы n/nthreads.

Ответ 2

С++ 11 §29.5/1 говорит

Существует общий шаблонный шаблон. Тип аргумента шаблона T должен быть тривиально скопируемым (3.9).

Что означает тривиальное копирование?

В §3.9 говорится

Скалярные типы, тривиально-скопируемые типы классов (раздел 9), массивы таких типов и cv-квалификационные версии этих типов (3.9.3) совместно называются тривиально-скопируемыми типами.

Для типов классов (из которых std::vector is):

Тривиально-скопируемый класс - это класс, который:

  • не имеет нетривиальных конструкторов копирования
  • не имеет нетривиальных конструкторов перемещения
  • не имеет нетривиальных операторов присваивания копий
  • не имеет нетривиальных операторов присваивания перемещения
  • имеет тривиальный деструктор

В соответствии с этим списком std::vector не является тривиально скопируемым, поэтому вы не можете использовать std::atomic<std::vector<int>>.

Поскольку вы знаете размер заранее, и поскольку вам не нужно использовать методы, которые требуют, чтобы вектор перераспределялся в другом месте (например, push_back). Вы можете использовать std::vector<int>::resize или конструктор размера для предварительного распределения и предконструкции требуемый int s. Поэтому ваши параллельные потоки не должны работать с самим вектором, а с элементами.

Если нет доступа из разных потоков к одному и тому же элементу, условие расы отсутствует.

То же самое относится к int k[1000], который тривиально можно копировать. Но вам это не нужно, поскольку потоки не меняют сам массив/вектор/список, а элементы.

Ответ 3

Атомный может быть создан с помощью тривиально копируемых типов. Вектор не такой тип.