1

次のコードは、OpenMP タスクの 1 つが が指す要素の 1 つを削除するため、クラッシュし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
}
4

2 に答える 2

1

複数のスレッドを使用してノードを消去std::listするのは非常に注意が必要です。クリティカル ゾーンのノードを消去するだけでなく、リスト トラバーサルに使用されるイテレータにも注意する必要があります。

1 つのスレッドを使用して を実行し++it、別のスレッドを使用して を実行しlist.erase(it)ている場合、 が指すノードが が完了itする前に既に消去されている可能性があり、存在しないノードを指す反復子で実行すると、未定義の動作が発生します。++it++

考えられる解決策の 1 つは、ノードが消去/変更される前に確実に実行することです。 ++it@sehe で示されているよう++itに、erase.

#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
}
于 2013-10-31T11:42:43.883 に答える
0

終了イテレータを過ぎて実行される可能性があるため (最後の要素を消去した場合)、 のit++後にインクリメントするべきではありません。erase

簡単なデモンストレーション ( がassert成功する様子を見てください!):

#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!
    }
}
于 2013-10-31T09:52:55.947 に答える