Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::vector push_back fails when used in a parallel for loop

I have a code that is as follow (simplified code):

for( int i = 0; i < input.rows; i++ )
{
    if(IsGoodMatch(input[I])
    { 
        Newvalues newValues;
        newValues.x1=input.x1;
        newValues.x2=input.x1*2;
        output.push_back( newValues);
    }
} 

This code works well, but if I want to make it parallel using omp parallel for, I am getting error on output.push_back and it seems that during vector resize, the memory corrupted.

What is the problem and how can I fix it?

How can I make sure only one thread inserting a new item into vector at any time?

like image 717
mans Avatar asked Oct 09 '13 09:10

mans


People also ask

Is Emplace_back faster than Push_back?

With the simple benchmark here, we notice that emplace_back is 7.62% faster than push_back when we insert 1,000,000 object (MyClass) into an vector.

Does std::vector Push_back make a copy?

Yes, std::vector<T>::push_back() creates a copy of the argument and stores it in the vector.

How vector works What's the complexity of the Push_back?

push_back is amortized O(1) time complexity. There is normally extra space and no extra work, the item is inserted in one iteration. When extra space is required, there may be an O(N) copy loop, not O(N^2).


3 Answers

The simple answer is that std::vector::push_back is not thread-safe.

In order to safely do this in parallel you need to synchronize in order to ensure that push_back isn't called from multiple threads at the same time.

Synchronization in C++11 can easily be achieved by using an std::mutex.

like image 85
Agentlien Avatar answered Oct 27 '22 01:10

Agentlien


std::vector's push_back can not guarantee a correct behavior when being called in a concurrent manner like you are doing now (there is no thread-safety).

However since the elements don't depend on each other, it would be very reasonable to resize the vector and modify elements inside the loop separately:

output.resize(input.rows);
int k = 0;

#pragma omp parallel for shared(k, input)
for( int i = 0; i < input.rows; i++ )
{
    if(IsGoodMatch(input[I])
    { 
        Newvalues newValues;
        ...
        // ! prevent other threads to modify k !
        output[k] = newValues;
        k++;
        // ! allow other threads to modify k again !
    }
} 

output.resize(k);

since the direct access using operator[] doesn't depend on other members of std::vector which might cause inconsistencies between the threads. However this solution might still need an explicit synchronization (i.e. using a synchronization mechanism such as mutex) that will ensure that a correct value of k will be used.

"How can I make sure only one thread inserting a new item into vector at any time?"

You don't need to. Threads will be modifying different elements (that reside in different parts of memory). You just need to make sure that the element each thread tries to modify is the correct one.

like image 40
LihO Avatar answered Oct 27 '22 01:10

LihO


Use concurrent vector

#include <concurrent_vector.h>

Concurrency::concurrent_vector<int> in c++11.

It is thread safe version of vector.

like image 21
ahmed raza Avatar answered Oct 27 '22 01:10

ahmed raza