2013-10-30 42 views
1

以來的OpenMP的任務之一的下一個代碼崩潰刪除由it指出的要素之一中的一個。我怎樣才能解決這個問題?代碼必須使用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 
} 
+0

用'#pragma omp single'就是這個連線程有關嗎? – sehe

+0

我回答。兩個鏈接:[選擇不破(http://www.codinghorror.com/blog/2008/03/the-first-rule-of-programming-its-always-your-fault.html)和[無人寫入測試用例了](http://kera.name/articles/2013/10/nobody-writes-testcases-any-more/) – sehe

+0

它是'local_it =它++;','未= local_it ++它;' .... – kangshiyin

回答

1

刪除節點是非常棘手的。您不僅必須擦除關鍵區域中的節點,還要照顧用於列表遍歷的迭代器。

當您使用一個線程來執行++it和其他線程做list.erase(it),你可能會發現,通過it指向的節點可以已經被擦除之前++it完成,並指向一個非迭代器做++存在節點將導致未定義的行爲。

一個可能的解決方案是,可以確保++it完成節點被刪除/改變之前,通過@sehe指示,你不應該++iterase之後。

#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 
} 
+4

「指向不存在的節點的迭代器肯定會導致程序崩潰」是誤導性的。痛苦的是:它不會_definitely_。機會是,它不會,只是把你的貓賣給你的牙醫。 – sehe

+0

@sehe:添加一個到我的收藏UB症狀 –

+0

@sehe對不起,非母語的人在這裏。我的意思是「在指向不存在節點的迭代器上執行'++'」會導致程序崩潰。我們可以這樣說嗎? – kangshiyin

0

你根本不應該erase後遞增it++,因爲你可能跑過去結束迭代器(如果你刪除的最後一個元素)。

一個簡單的演示(觀看assert如何成功!):從std::list使用多線程

#include <list> 
#include <cassert> 

struct Class { int getNumber() const { return 0; } }; 

int main() 
{ 
    std::list<Class*> l { new Class() }; 
    for(auto it = l.begin(); it != l.end();) 
    { 
     if((*it)->getNumber() == 0) 
      it = l.erase(it); 

     assert(it == l.end()); 

     it++; // OOOOOPS! 
    } 
} 
+0

'it'是線程局部變量在任務由'firstprivate'定義,所以'++ it'不會更改任務以外的任何東西。 – kangshiyin

+0

@Eric是的,我不能加快基於任務的openmp。爲了防止混淆,刪除了'修復'的想法 – sehe