2016-12-16 2 views
3

Мне нужно создать вектор из k элементов. Каждый поток будет создавать свою часть, скажем, k * 25% и должен поместить ее в вектор по любому индексу. Изгнанные из этой example я собирался сделать что-то вроде этого:Заполнение вектора параллельно, не важно

std::atomic<std::vector<aClass<templatedType>>> H; 

, но это не будет работать:

/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/atomic:823:13: error: 
     _Atomic cannot be applied to type 
     'std::__1::vector<StableHashFunction<int>, 
     std::__1::allocator<StableHashFunction<int> > >' which is not trivially 
     copyable 
    mutable _Atomic(_Tp) __a_; 

, так как это не тривиально копируемыми - и обходной путь не мила. Кроме того, мне нужно, чтобы он был атомарным?

Это вопрос, когда меня не волнует порядок, должен ли я использовать атом? Другими словами, выполняют ли данные скачки только порядок элементов, или они могут вызывать другие побочные эффекты, например, уклонение элемента (поэтому вместо k элементов в конце есть только k-1)?

+0

'push_back()' или 'emplace_back()' не атомарные операции, таким образом, вы должны защищать их с какой-то механизм синхронизации как 'станд :: mutex'. –

+0

Создайте вектор размера K, затем каждую часть обновления потока вектора, чтобы вы не делили данные между потоками. – Jarod42

+0

@ Jarod42 Это была моя первая мысль, но для этого вам нужно по умолчанию построить все элементы в векторе. – NathanOliver

ответ

4

При попытке вставки элементов параллельно, проблемы случаются только тогда, когда вектор должен изменить его размер: параллельные вставки должны обновить одни и то же место в памяти, вызывая неправильное поведение (аварии, потерянные вещи и т.д.)

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

Этот подход требует конструктора по умолчанию для векторного элемента и предварительного знания точного количества элементов, которые каждый поток собирается разместить в векторе. Например, если вы знаете, что поток 0 будет размещать 100 элементов, поток 1 будет размещать 120 элементов, а поток 2 будет размещать 110 элементов, вы предварительно выделите вектор из 100 + 120 + 110 элементов и дать каждому потоку свой собственный начальный индекс: 0, 100 и 220. Теперь каждый поток может помещать элементы в вектор без проблем с параллелизмом.

Vector subdivision

+0

Мне интересен линейный кеш. Что произойдет, если элементы с индексами 99 и 100 находятся в одной строке кеша? – Amadeus

+0

@Amadeus Это называется ложным совместным использованием и является серьезной проблемой. Если нити начинаются с начала и идут до конца, вы, вероятно, не увидите этого. – NathanOliver

+0

@Amadeus Это не должно создавать большой проблемы: ядро, которое происходит для записи, сначала приведет к недействительности строки кэша другого ядра, поэтому при следующем запросе данных он должен будет считывать из памяти. Все, что вы видите, это небольшое замедление, которое даже не должно быть проблемой, потому что к моменту, когда первый поток собирается записать в местоположение 99, второй поток должен быть длинным с местоположением 100, на место 199 или около того. – dasblinkenlight

1

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

+0

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