C++ 任务删除其中一个迭代对象时会导致segfault
下一个代码崩溃,因为其中一个OpenMP任务删除了它所指向的一个元素。我如何解决这个问题?代码必须使用OpenMP任务来实现C++ 任务删除其中一个迭代对象时会导致segfault,c++,iterator,openmp,C++,Iterator,Openmp,下一个代码崩溃,因为其中一个OpenMP任务删除了它所指向的一个元素。我如何解决这个问题?代码必须使用OpenMP任务来实现 #pragma omp parallel { #pragma omp single nowait { for (std::list<Class*>::iterator it = myClass.begin(); it != myClass.end();) { if ((*it)->getNumber() == 0
#pragma omp parallel
{
#pragma omp single nowait
{
for (std::list<Class*>::iterator it = myClass.begin(); it != myClass.end();) {
if ((*it)->getNumber() == 0) {
#pragma omp critical
it = myClass.erase(it);
}
else {
#pragma omp task firstprivate(it)
{
bool result = (*it)->function(t);
if ( result ) {
#pragma omp critical
it = myClass.erase(it);
}
}
}
++it;
}
}
#pragma omp taskwait
}
#pragma omp并行
{
#pragma-omp-single-nowait
{
对于(std::list::iterator it=myClass.begin();it!=myClass.end();){
如果((*it)->getNumber()==0){
#pragma-omp-critical
it=myClass.erase(它);
}
否则{
#pragma omp任务第一个专用(it)
{
bool result=(*it)->函数(t);
如果(结果){
#pragma-omp-critical
it=myClass.erase(它);
}
}
}
++它;
}
}
#pragma omp taskwait
}
您不应该在erase
之后增加it++
,因为您可能会跑过结束迭代器(如果删除最后一个元素)
一个简单的演示(看看断言如何成功!)
#包括
#包括
结构类{int getNumber()常量{return 0;}};
int main()
{
std::list l{new Class()};
对于(自动it=l.begin();it!=l.end();)
{
如果((*it)->getNumber()==0)
它=l.擦除(它);
断言(it==l.end());
it++;//oooops!
}
}
您不应该在erase
之后增加it++
,因为您可能会跑过结束迭代器(如果删除最后一个元素)
一个简单的演示(看看断言如何成功!)
#包括
#包括
结构类{int getNumber()常量{return 0;}};
int main()
{
std::list l{new Class()};
对于(自动it=l.begin();it!=l.end();)
{
如果((*it)->getNumber()==0)
它=l.擦除(它);
断言(it==l.end());
it++;//oooops!
}
}
使用多线程从std::list
中删除节点非常棘手。您不仅要删除关键区域中的节点,还要注意用于列表遍历的迭代器
当您使用一个线程执行++it
和其他线程执行列表。擦除(it)
时,您可能会发现it
指向的节点可能在++it
完成之前已经被擦除,而在指向不存在节点的迭代器上执行++
将导致未定义的行为
一种可能的解决方案是,确保在删除/更改节点之前执行++it
,并且如@sehe所示,在执行删除之后,不应执行++it
#pragma omp parallel
{
#pragma omp single nowait
{
for (std::list<Class*>::iterator it = myClass.begin(); it != myClass.end();) {
if ((*it)->getNumber() == 0) {
#pragma omp critical
it = myClass.erase(it);
}
else {
std::list<Class*>::iterator local_it=it++;
#pragma omp task firstprivate(local_it)
{
bool result = (*local_it)->function(t);
if ( result ) {
#pragma omp critical
myClass.erase(local_it);
}
}
}
}
}
#pragma omp taskwait
}
#pragma omp并行
{
#pragma-omp-single-nowait
{
对于(std::list::iterator it=myClass.begin();it!=myClass.end();){
如果((*it)->getNumber()==0){
#pragma-omp-critical
it=myClass.erase(它);
}
否则{
std::list::iterator local_it=it++;
#pragma omp task firstprivate(本地_it)
{
bool result=(*local_it)->函数(t);
如果(结果){
#pragma-omp-critical
清除(本地的);
}
}
}
}
}
#pragma omp taskwait
}
使用多线程从std::list
中删除节点非常棘手。您不仅要删除关键区域中的节点,还要注意用于列表遍历的迭代器
当您使用一个线程执行++it
和其他线程执行列表。擦除(it)
时,您可能会发现it
指向的节点可能在++it
完成之前已经被擦除,而在指向不存在节点的迭代器上执行++
将导致未定义的行为
一种可能的解决方案是,确保在删除/更改节点之前执行++it
,并且如@sehe所示,在执行删除之后,不应执行++it
#pragma omp parallel
{
#pragma omp single nowait
{
for (std::list<Class*>::iterator it = myClass.begin(); it != myClass.end();) {
if ((*it)->getNumber() == 0) {
#pragma omp critical
it = myClass.erase(it);
}
else {
std::list<Class*>::iterator local_it=it++;
#pragma omp task firstprivate(local_it)
{
bool result = (*local_it)->function(t);
if ( result ) {
#pragma omp critical
myClass.erase(local_it);
}
}
}
}
}
#pragma omp taskwait
}
#pragma omp并行
{
#pragma-omp-single-nowait
{
对于(std::list::iterator it=myClass.begin();it!=myClass.end();){
如果((*it)->getNumber()==0){
#pragma-omp-critical
it=myClass.erase(它);
}
否则{
std::list::iterator local_it=it++;
#pragma omp task firstprivate(本地_it)
{
bool result=(*local_it)->函数(t);
如果(结果){
#pragma-omp-critical
清除(本地的);
}
}
}
}
}
#pragma omp taskwait
}
与#pragma omp single
这是否与线程相关?我回答。两个链接:它是local_It=It++代码>,而不是local\u it=++it代码>…与#pragma omp single
这甚至与线程相关吗?我回答。两个链接:它是local_It=It++代码>,而不是local\u it=++it代码>…it
是任务中的线程局部变量,由firstprivate
定义,因此++it
不会更改任务之外的任何内容。@Eric是的,我没有跟上基于任务的openmp的速度。删除了防止混淆的“修复”概念它是任务中的线程局部变量,由firstprivate
定义,因此++it
不会更改任务之外的任何内容。@Eric是的,我没有跟上基于任务的openmp的速度。删除了“修复”概念以防止混淆“指向不存在节点的迭代器肯定会使程序崩溃”是误导性的。痛苦的是:它肯定不会。很可能不会,它只是把你的猫卖给你的牙医。@sehe:把那只猫加入我的收藏symptoms@sehe对不起,这里不是母语人士。我的意思是“在指向不存在节点的迭代器上执行++
”会使程序崩溃。我们能这么说吗?不,因为