0

複数のスレッドで実行しているときにdoubleの配列の最大値を計算するC(gcc)関数を作成しようとしています。サイズの配列を作成しますomp_get_num_threads。この配列には、この小さな配列を最終的に最大化する前に、各スレッドの極大値を格納します。コードは(多かれ少なかれ)次のとおりです。

int i;
double *local_max;
double A[1e10]; //made up size

#pragma omp parallel
{

#pragma omp master
{
local_max=(double *)calloc(omp_get_num_threads(),sizeof(double));
}

#pragma omp flush  //so that all threads point 
                   //to the correct location of local_max

#pragma omp for

for(i=0;i<1e10;i++){
   if(A[i]>local_max[omp_get_thread_num()])
      local_max[omp_get_thread_num()]=A[i];
}

}

free(local_max);

ただし、これはsegfaultにつながり、valgrindは初期化されていない変数の使用について不平を言います。結局のところ、local_maxは、for構成に入る前にすべてのスレッドで実際に更新されるわけではありません。私#pragma omp flushはそれをすべきだと思いましたか?に置き換えると#pragma omp barrier、すべて正常に動作します。

誰かが私に何が起こっているのか説明してもらえますか?

4

3 に答える 3

3

問題の最も簡単な解決策は、どのスレッドが割り当てを行うかは実際には問題ではないため、master構成を単純に置き換えるsingleことです(NUMAマシンで実行している場合を除きますが、他にも心配することがたくさんあります):

#pragma omp single
{
   local_max=(double *)calloc(omp_get_num_threads(),sizeof(double));
}

masterとの微妙な違いsingleは、 の最後に暗黙のバリアがあり、 の最後にはそのsingleようなバリアが存在しないことですmastersingleこの暗黙のバリアは、ブロックを実行するスレッドがブロックの最後に到達するまで、他のすべてのスレッドを待機させます (nowait句が指定されていない限り、暗黙のバリアが削除されます)。バリアをmaster明示的に追加する必要があります。masterOpenMP* 設計者が、暗黙のバリアを持たないという決定を下した理由は、私の理解を超えてsingleいます。

于 2013-02-18T20:40:01.983 に答える
1

メモリ割り当てが完了したことを確認するためのバリアを配置する必要があります。メモリ割り当ては時間のかかる操作であり、最後の for ループの実行が開始されると、local_max は適切に割り当てられたスペースを指していません。動作を示すために、以下のコードを変更しました。

int i;
double *local_max;
omp_set_num_threads(8);
#pragma omp parallel
{
#pragma omp master
    {           
        for(int k = 0; k < 999999; k++) {} // Lazy man's sleep function
        cout << "Master start allocating" << endl;
        local_max=(double *)calloc(omp_get_num_threads(),sizeof(double));
        cout << "Master finish allocating" << endl;
    }
#pragma omp flush 
#pragma omp for
    for(i=0;i<10;i++){
        cout << "for : " << omp_get_thread_num()  << " i: " << i << endl;
    }
}
free(local_max);
getchar();
return 0;
于 2013-02-16T00:41:03.363 に答える