7

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?

4

6 回答 6

8

简单的答案是这std::vector::push_back不是线程安全的。

为了安全地并行执行此操作,您需要同步以确保push_back不会同时从多个线程调用。

C++11 中的同步可以通过使用std::mutex.

于 2013-10-09T09:42:58.153 回答
6

std::vector'push_back不能保证像现在这样以并发方式调用时的正确行为(没有线程安全性)。

但是,由于元素之间不相互依赖,因此resize在循环中分别修改向量和修改元素是非常合理的:

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);

因为直接访问 usingoperator[]不依赖于std::vector可能导致线程之间不一致的其他成员。然而,此解决方案可能仍需要显式同步(即使用诸如互斥锁之类的同步机制),以确保使用正确的值k

“如何确保任何时候只有一个线程将新项目插入向量中?”

你不需要。线程将修改不同的元素(驻留在内存的不同部分)。您只需要确保每个线程尝试修改的元素是正确的。

于 2013-10-09T09:41:59.947 回答
2

使用并发向量

#include <concurrent_vector.h>

Concurrency::concurrent_vector<int>在 C++11 中。

它是向量的线程安全版本。

于 2017-06-16T15:29:08.920 回答
2

在. #pragma omp critical_push_back

于 2020-03-30T10:47:25.200 回答
0

我通过派生标准类来解决类似的问题,std::vector只是为了实现一个atomic_push_back适合在OpenMP范式中工作的方法。

这是我的“OpenMP-safe”矢量实现:

template <typename T>
class omp_vector : public std::vector<T>
{
    private:
    omp_lock_t lock;
    public:
    omp_vector()
    {
         omp_init_lock(&lock);
    }
    void atomic_push_back(T const &p)
    {
        omp_set_lock(&lock);
        std::vector<T>::push_back(p);
        omp_unset_lock(&lock);
    }
};

当然你必须包括omp.h. 那么您的代码可能如下所示:

opm_vector<...> output;

#pragma omp parallel for shared(input,output)     
for( int i = 0; i < input.rows; i++ )
{
    if(IsGoodMatch(input[I])
    { 
        Newvalues newValues;
        newValues.x1=input.x1;
        newValues.x2=input.x1*2;
        output.atomic_push_back( newValues);
    }
}

如果您仍然需要在output代码的非并行部分的其他地方使用向量,您可以使用普通push_back方法。

于 2022-01-24T12:02:48.623 回答
-9

您可以尝试使用互斥锁来解决问题。通常我更喜欢自己实现这样的事情;

static int mutex=1;
int signal(int &x)
{
    x+=1;
    return 0;
}
int wait(int &x)
{
    x-=1;
    while(x<0);
    return 0;
}
for( int i = 0; i < input.rows; i++ )
{
    if(IsGoodMatch(input[I])
    {
        Newvalues newValues;
        newValues.x1=input.x1;
        newValues.x2=input.x1*2;
        wait(mutex);
        output.push_back( newValues);
        signal(mutex);
    }
} 

希望这会有所帮助。

于 2013-10-09T09:55:20.663 回答