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

C++ 并行实例化类导致与内存相关的错误,c++,memory-management,parallel-processing,scope,openmp,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); } 然而,有没有一种方法可以将两者并行?

下面的并行循环会导致后面的几个错误:

#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);
}
然而,有没有一种方法可以将两者并行?我假设这是实例指针的一个简单的作用域问题,因为每个线程都有自己的作用域,之后我需要访问并行区域之外的每个实例的地址。主程序的其余部分基本上是

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);
for(i=0;i<(int)my_instances_vector.size();i++){
我的_实例_向量[i]->print_results();//应按顺序进行
}
my_实例_vector.clear();
返回(退出成功);

我尝试了
lasprivate
和/或
shared
的所有可能组合,用于
cur
my\u实例\u vector
。它导致了相同的错误或竞争条件。我找到的唯一“解决方案”是取消对实例化的分析。我所做的有什么错误吗?或者这是一个特定于我的课程内容的错误吗?类构造函数基本上根据传递的参数定义一些字段的值。这涉及到一些动态分配。也许这些地址正在“丢失”?

问题在于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());
}
#pragma omp并行
{
向量my_实例_向量_私有;
#计划的pragma omp(动态,omp_get_num_procs())nowait
对于(int i=0;i<(int)my_vector.size();i++){
My_class*cur=新My_class(args);
cur->do_work();
我的实例向量私有。向后推(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
问题(正如@zboson正确指出的)是
推回过程中的数据争用。然而,我想提出一个不同的解决方案,它可能更容易实施:

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
}
size\u t offset=my\u instances\u vector.size;
//为正确数量的指针预先分配空间
//并将它们设置为空ptr
my_instances_vector.insert(my_instances_vector.end()、my_vector.size()、nullptr);
#计划的pragma omp并行(动态、块大小)
对于(size_t ii=0;iido_work();//处理它
}
正如您所看到的,代码是无数据竞争的,因为每个线程都在
my\u instances\u vector
的元素上工作


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

cur
应该是私有的(或在并行区域内声明),对
std::vector::push_back()
的调用应该受到互斥锁的保护(关键部分)。Z Boson使用私有向量的解决方案更好,因为它减少了时间开销。出于好奇:为什么计划中的块大小设置为
omp_get_num_procs()
?@Massimiliano我们在对块大小进行一些测试,没有特别的原因。不幸的是,我正在处理的项目使用了原始指针和std::vector。非常聪明的方法,谢谢!+1,因为在这种情况下,你的答案显然比我的好。另一方面,我想不出一种情况,我想使用std::vector来提高性能。
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
}