C++ 任务删除其中一个迭代对象时会导致segfault

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

下一个代码崩溃,因为其中一个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 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对不起,这里不是母语人士。我的意思是“在指向不存在节点的迭代器上执行
++
”会使程序崩溃。我们能这么说吗?不,因为