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++11std::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
}