2011-09-16 9 views
0

私は利用可能なコンパイラ(xlCとgcc)で動作するが、完全に準拠しているかどうかわからない(明示的に許可しないOpenMP 3.0仕様で何も見つからなかった):firstprivate変数の構築で許可されたOpenMPコールとディレクティブ?

#include <iostream> 
#include <vector> 
#include <omp.h> 

struct A { 
    int tid; 
    A() : tid(-1) { } 
    A(const A&) { tid = omp_get_thread_num(); } 
}; 

int main() { 
    A a; 

    std::vector<int> v(10); 
    std::vector<int>::iterator it; 
#pragma omp parallel for firstprivate(a) 
    for (it=v.begin(); it<v.end(); ++it) 
    *it += a.tid; 

    for (it=v.begin(); it<v.end(); ++it) 
    std::cout << *it << ' '; 
    std::cout << std::endl; 
    return 0; 
} 

私の動機はどのように多くのスレッドと セクション(私も処理されている各要素のためにそれを呼び出すしたくない)のためのOMP並列に各スレッドのIDを把握することです。私が未定義の動作を引き起こしている可能性はありますか?

+0

コードが壊れています。 (1) 'it!= v.end()'、(2) 'it + = a.tid':これはデータ競合を引き起こします。あなたは正確に何をしたいですか? – minjang

+0

データ競争は正確にどちらですか?私はベクトルのすべての値を繰り返し処理していますが、インデックスとv.size()を使うことと変わりはありません – ipapadop

答えて

2

私はループから並列領域(の開始)を分離し、TIDを保つためにプライベート変数を使用する:

std::vector<int>::iterator it; 
int tid; 
#pragma omp parallel private(tid) 
{ 
    tid = omp_get_thread_num(); 
    #pragma omp for 
    for (it=v.begin(); it<v.end(); ++it) 
     *it += tid; 
} 

追加:

:以下私は あなたのコードが準拠していると思わせるthe OpenMP specification(セクション2.9.3.4)からの引用であるので、UB生成しません(ただし、下記の別追加を参照してください)

...新しいリスト項目は、構造の前にある元のリスト項目から初期化されます。新しいリスト項目の初期化は、構造内の任意のステートメントのリスト項目を参照するタスクごとに1回実行されます。初期化は、構成の実行前に行われます。 parallel又はtask構築物上firstprivate句の

は、新しいリスト項目の初期値は、構築物が検出された作業領域内の構築物の直前に存在する元のリスト項目の値です。

C/C++:...クラス型の変数の場合、コピーコンストラクタが呼び出されて初期化が実行されます。クラス型の異なる変数のコピーコンストラクタが呼び出される順序は不定です。

C/C++ 句 に現れるクラス型(またはその配列)の変数は、クラス型のためのアクセス可能な明瞭なコピーコンストラクタを必要とします。

追加-2:ただし、firstprivate変数のコピーコンストラクタを実行するスレッドは指定されていません。理論的には、変数のすべてのコピーについてリージョンのマスタースレッドが行うことができます。この場合、omp_get_thread_num()の値はすべてのコピーで等しくなります。0または入れ子になった並列領域の場合は、外側領域のスレッド番号です。 OpenMPの観点から定義された動作であるため、プログラムでデータ競合が発生する可能性があります。

+0

Alexeyに感謝します。それは私の質問に答えます。オブジェクトコピーの作成順序はそれほど重要ではありません。ただし、どのスレッドが実行されるかを指定しないという事実は潜在的な危険です。パフォーマンス上の理由から実装が別のスレッドのオブジェクトをインスタンス化するスレッドを1つ持つことは期待していませんが、そうしても驚くことはありません。 – ipapadop

0

ベクトルを反復処理するときは、!= v.end()を使用する必要があり、< v.end()は使用しないでください。ただし、この場合、並列forループはもはや有効ではありません。私は、次のようにコードのその部分を再構築することになる。

#pragma omp parallel for firstprivate(a) 
    for (int i = 0 ; i < v.size() ; i++) 
    v[i] += a.tid; 
+0

このタイプの繰り返しはOpenMP 3.0で可能です(http://wikis.sun.com/pages/viewpageも参照してください)。 .action?pageId = 57508020)。 – ipapadop

関連する問題