2012-01-17 24 views
2

各行がポイントを表し、各列がこのポイントとデータ内の他のすべてのポイントとの間の距離である距離行列を構築しています。しかし、私はそれを並列化しようとすると、私はセグメンテーションフォールトエラーを取得します。次は私のすべてのデータを含むマップであるパラレルのための私のコードです。ここの助けは非常に高く評価されます。セグメント化エラーopenmpエラー

map< int,string >::iterator datIt; 
map< int,string >::iterator datIt2; 
map <int, map< int, double> > dist; 
int mycont=0; 
datIt=dat.begin(); 
int size=dat.size(); 
#pragma omp parallel //construct the distance matrix 
{ 
    #pragma omp for 
    for(int i=0;i<size;i++) 
    { 
    datIt2=dat.find((*datIt).first); 
    datIt2++; 
    while(datIt2!=dat.end()) 
    { 
     double ecl=0; 
     int c=count((*datIt).second.begin(),(*datIt).second.end(),delm)+1; 
     string line1=(*datIt).second; 
     string line2=(*datIt2).second; 
     for (int i=0;i<c;i++) 
     { 
     double num1=atof(line1.substr(0,line1.find_first_of(delm)).c_str()); 
     line1=line1.substr(line1.find_first_of(delm)+1).c_str(); 
     double num2=atof(line2.substr(0,line2.find_first_of(delm)).c_str()); 
     line2=line2.substr(line2.find_first_of(delm)+1).c_str(); 
     ecl += (num1-num2)*(num1-num2); 
     } 
     ecl=sqrt(ecl); 
     dist[(*datIt).first][(*datIt2).first]=ecl; 
     dist[(*datIt2).first][(*datIt).first]=ecl; 
     datIt2++; 
    } 
    datIt++; 
    } 
} 
+2

私たちがそのコードをデバッグすることを期待しているなら、クラッシュの時点で少なくともスタックトレースを提供することができます。 – NPE

+0

投稿する前にコードをインデントしてください。 –

答えて

3

私はそれはあなたのコードの唯一の問題であるかどうかわからないんだけど、(例えばstd::mapなど)標準コンテナは、あなたがそれらに書き込み、少なくとも場合は、スレッドセーフではありません。だからのようなあなたのmapsへの書き込みアクセスがあれば、#pragm omp criticalまたはmutexes(omp mutexまたはboostまたはC++ 11を使用する場合はboost::mutexを使用して)何らかの同期構造でマップへのアクセスをラップする必要があります。またはstd::mutexは)あまりにもオプションがあります

//before the parallel: 
omp_lock_t lock; 
omp_init_lock(&lock); 
... 

omp_set_lock(&lock); 
dist[(*datIt).first][(*datIt2).first]=ecl; 
dist[(*datIt2).first][(*datIt).first]=ecl; 
omp_unset_lock(&lock); 
... 

//after the parallel: 
omp_destroy_lock(&lock); 

それが何を持っているので、あなただけのdatから読み込まれているので、それはC++ 11で(のsyncronizationなしで問題ないはずです、少なくとも、C++ 03は全くthreadsafety(約保証がありませんスレッドのコンセプト)。同期をまだせずに、技術的には実装に依存する振る舞いを使用するのは、通常はうまくいくはずです。

さらに、データ共有を指定していないので、parallel領域外に宣言されたすべての変数はデフォルトで共有されます。したがって、datItdatIt2への書き込みアクセスも競合状態になります。 datIt2については、これはどちらかプライベートか、より良い最初の使用の時点でそれを宣言すると、それを指定することで回避することができます:あなたが反復処理したいと思われるので、datItのためにこれを解く

map< int,string >::iterator datIt2=dat.find((*datIt).first); 

は、もう少し問題があります地図の全長。

#pragma omp parallel //construct the distance matrix 
{ 
    map< int,string >::iterator datItLocal=datIt; 
    int lastIdx = 0; 
    for(int i=0;i<size;i++) 
    { 
     std::advance(datItLocal, i - lastIdx); 
     lastIdx = i; 
     //use datItLocal instead of datIt everytime you reference datIt in the parallel 
    //remove ++datIt 
    } 
} 

:(O(n)事前各反復を使用して、過度に高価ではありません)最も簡単な方法は(ちょうど速いアウトライン100%の正確性を保証していない)に応じて進められdatItのプライベートコピー、上で動作しているように思われますこの方法では、マップは反復されますomp_get_num_threads()回、しかしそれは動作するはずです。それが許容できないオーバーヘッドであれば、openmpのbidirectional iteratorでループするための代替ソリューションについてはthis answer of mineをご覧ください。

脇の下として:多分私は何かを逃したが、私にはdatItdatのイテレータであり、dat.find(datIt->first)が少し冗長であると思われるようだ。マップには指定されたキーを持つ要素が1つしかなく、datItという点があるので、これはdatIt2=datIt(私が間違っていれば私を修正する)という高価な方法のようです。

2

Girzzlyの回答に加えて、あなたはプライベートまたは共有を指定しません。これは通常、メモリのアクセスを制御しないことを意味します。並列領域を入力するときにdatIt firstprivateとdatIt2をプライベートに定義する必要があります。そうしないと、すべてのスレッドがその共有値を上書きしてsegfaultsになります。

ロックを使用する代わりに、私はクリティカルセクションを使用します。これは、より多くのopenmpishです。

+0

私は一般的にクリティカルセクションへのロックを優先しています。なぜなら、コードの他のポイントで共有データ構造へのアクセスを追加したいのではないかと思います。異なるクリティカルセクションが(私の知る限り)お互いに同期します。しかし、私はalswaysロックコードをRAIIクラスでラップするだろう、私は簡潔に私のサンプルではしなかった。私はあなたが私の答えに 'datIt'についてのポイントを追加すれば気にしないことを願っています – Grizzly

+0

それは問題ありません。私はOOCコードでopenmpを広範囲に使用していません。私は、コードが一度に1つのスレッドで実行されるので、お互いに同期することが何を意味するのか分かりません。さらに、クリティカルセクションの前後に暗黙のフラッシュが呼び出されるため、誰もが最新の状態になっています。 – Bort

+0

私は自分自身を100%確信しているわけではありませんが、ソースコードのさまざまな部分からアクセスすると、共有構造のアクセスを保護することはできません。同時にクリティカルセクションを指定すると、異なるクリティカルセクションで同時にスレッドを禁止することはできません(本当に無駄に思えるのであれば)。したがって、クリティカルセクションは、特定のデータ構造ではなく、コード内の特定の位置を保護します。それは本当に私にとっては良い考えのようには見えません。 – Grizzly