Здесь вы видите эффект небезопасной функции потока, вызываемой несколькими потоками.Внутренне push_back
делает что-то вроде следующего в псевдокоде
if reallocation needed:
reallocate
construct new object at &data[size]
++size
Теперь попробуйте представить различные потоки, выполняющие вышеуказанный код одновременно.Что произойдет, если оба потока увидят необходимость перераспределения и попыток сделать это одновременно.Что если они оба построят объект на &data[size]
, потому что они оба достигли этой точки до ++size
?Обратите внимание, что даже попытка увеличения на той же строке, что и конструкция, не будет работать, потому что они по-прежнему являются отдельными неатомарными операциями.
Что вы действительно хотите сделать, так это создать цикл строго потокобезопасных операций, таких какследующий.
int main() {
std::vector<int> vec(301);
#pragma omp parallel for
for (int i = 0; i <= 300; i++) {
vec[i]= i;
}
std::cout << vec.size() << std::endl;
}
В этом случае каждый поток обращается к vec[i]
с уникальным i
.Таким образом, никакие операции не происходят одновременно с одними и теми же объектами.Это абсолютно безопасно.
Чтобы ответить на ваш дополнительный вопрос, нельзя одновременно ввести push_back
в вектор.Вам нужно будет синхронизировать ваши вызовы push_back
, что сделает их медленнее, чем непараллельный способ.Другое решение - заполнить локальные контейнеры потоков, а затем объединить их.Но всякий раз, когда простое решение, которое я показал выше, применимо, оно также будет быстрее, чем альтернативы.