并行实例化类导致与内存相关的错误

时间:2014-09-26 20:01:08

标签: c++ memory-management parallel-processing scope openmp

下面的并行循环导致以后出现几个错误:

#pragma omp parallel for schedule(dynamic, omp_get_num_procs())
for (int i = 0; i < (int)my_vector.size(); i++) {
    cur = new My_Class(args);
    cur->do_work();
    my_instances_vector.push_back(cur);
}

有时程序只是段错误,有时它会提供memory corruption或其他与访问相关的错误,有时会导致意外行为。按顺序执行实例化并且并行工作可以解决问题:

for (int i = 0; i < (int)my_vector.size(); i++) {
    cur = new My_Class(args);
    my_instances_vector.push_back(cur);
}

#pragma omp parallel for schedule(dynamic, omp_get_num_procs())
for (i = 0; i < (int)my_instances_vector.size(); i++) {
    my_instances_vector[i]->do_work();
}

然而,有没有办法让它们并行?我认为这是一个简单的范围问题与实例指针,因为每个线程都有自己的范围,然后我需要访问并行区域外的每个实例的地址。主程序的其余部分基本上是

for (i = 0; i < (int)my_instances_vector.size(); i++) {
    my_instances_vector[i]->print_results(); // Should be done sequentially
}
my_instances_vector.clear();
return(EXIT_SUCCESS);

我为lasprivateshared尝试了cur和/或my_instances_vector的所有可能组合。它导致了相同的错误或竞争条件。我找到的唯一“解决方案”是无实例化实例化。我正在做什么有什么问题,或者这是我班级内容的特定错误?类构造函数基本上根据传递的参数定义某些字段的值。其中涉及一些动态分配。也许这些地址“丢失了”?

2 个答案:

答案 0 :(得分:2)

问题(正如@zboson正确指出的那样)是push_back期间的数据争用。不过,我想提出一个不同的解决方案,这可能更容易实现:

size_t offset = my_instances_vector.size;
// Pre-allocate space for the right number of pointers
// and set them to nullptr
my_instances_vector.insert(my_instances_vector.end(),my_vector.size(),nullptr);
#pragma omp parallel for schedule(dynamic, chunksize)
for (size_t ii = 0; ii < my_vector.size(); ii++) {
    my_instances_vector[offset + ii] = new My_Class(args); // Create the object 
    my_instances_vector[offset + ii]->do_work(); // work on it
}

正如您所看到的,代码是无数据争用的,因为每个线程都在其my_instances_vector元素上工作。

未请求建议:请关注内存管理!在向量中使用原始指针可能会在程序中留下泄漏,并且会导致代码难以维护,因为向量不负责删除使用new分配的资源。我建议看看RAII习语和C ++ 11 std::shared_ptr及相关方法(例如make_shared替换new)。

答案 1 :(得分:1)

问题是std :: vector不是线程安全的。每个线程都可以增加向量的大小并更改其内存位置。修复此问题的方法是让每个线程写入其自己的私有版本的向量,然后将它们合并到一个关键部分。在你的情况下,你可以这样做

#pragma omp parallel 
{
    vector<My_class*> my_instances_vector_private;
    #pragma omp for schedule(dynamic, omp_get_num_procs()) nowait
    for (int i = 0; i < (int)my_vector.size(); i++) {
        My_class *cur = new My_Class(args);
        cur->do_work();
        my_instances_vector_private.push_back(cur);
    }
    #pragma omp critical
    my_instances_vector.insert(my_instances_vector.end(), my_instances_vector_private.begin(), my_instances_vector_private.end());
}

这假定args是一个常数,或者它只是i的函数而不是i-1的函数。 {{1}}。