OpenMP の各内部ループのスレッドを開始する
-
19-09-2019 - |
質問
私は OpenMP を初めて使用するので、2D 配列内の各項目を処理する個別のスレッドを開始しようとしています。
つまり、本質的には次のようになります。
for (i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
a[i][j] = b[i][j] + c[i][j];
私がやっていることはこれです:
#pragma omp parallel for shared(a,b,c) private(i,j) reduction(+:diff) schedule(dynamic)
for (i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
a[i][j] = b[i][j] + c[i][j];
これは実際に各 2D アイテムのスレッドを開始しますか、それとも開始しませんか?それをどうやってテストすればいいでしょうか?それが間違っている場合、正しい方法は何ですか?ありがとう!
注記:コードが大幅に簡略化されました
解決
コードサンプルでは外側のループのみが並列になっています。印刷してテストできます omp_get_thread_num()
内側のループでそれがわかります。 i
, 、スレッド番号は同じです (もちろん、異なる実行では異なる結果が得られるため、このテストは決定的なものではなく実証的なものです)。たとえば、次のようになります。
#include <stdio.h>
#include <omp.h>
#define dimension 4
int main() {
#pragma omp parallel for
for (int i = 0; i < dimension; i++)
for (int j = 0; j < dimension; j++)
printf("i=%d, j=%d, thread = %d\n", i, j, omp_get_thread_num());
}
わかりました:
i=1, j=0, thread = 1
i=3, j=0, thread = 3
i=2, j=0, thread = 2
i=0, j=0, thread = 0
i=1, j=1, thread = 1
i=3, j=1, thread = 3
i=2, j=1, thread = 2
i=0, j=1, thread = 0
i=1, j=2, thread = 1
i=3, j=2, thread = 3
i=2, j=2, thread = 2
i=0, j=2, thread = 0
i=1, j=3, thread = 1
i=3, j=3, thread = 3
i=2, j=3, thread = 2
i=0, j=3, thread = 0
コードの残りの部分については、新しい質問に詳細を記載することもできます (小さなサンプルから判断するのは困難です)。たとえば、次のようにすることはできません。 private(j)
いつ j
後から宣言されるだけです。上記の例では、自動的に非公開になります。私は推測する diff
はサンプルでは確認できない変数です。また、ループ変数 i
は自動的に非公開になります( バージョン2.5仕様 - 3.0 仕様でも同じです)
for for forまたは並列のfor-loopのループ反復変数は、そのコンストラクトの私的です。
編集:上記はすべて、あなたと私が示したコードに当てはまりますが、次の点に興味があるかもしれません。OpenMP バージョン 3.0 の場合 (例: gcc バージョン 4.4, 、ただしバージョン 4.3 ではありません) collapse
この節では、これまでと同じようにコードを書くことができますが、#pragma omp parallel for collapse (2)
両方の for ループを並列化するには (「 仕様).
編集:OK、gcc 4.5.0をダウンロードして上記のコードを実行しましたが、 collapse (2)
次の出力を取得すると、内部ループが並列化されたことが示されます。
i=0, j=0, thread = 0
i=0, j=2, thread = 1
i=1, j=0, thread = 2
i=2, j=0, thread = 4
i=0, j=1, thread = 0
i=1, j=2, thread = 3
i=3, j=0, thread = 6
i=2, j=2, thread = 5
i=3, j=2, thread = 7
i=0, j=3, thread = 1
i=1, j=1, thread = 2
i=2, j=1, thread = 4
i=1, j=3, thread = 3
i=3, j=1, thread = 6
i=2, j=3, thread = 5
i=3, j=3, thread = 7
コメント ここ (「回避策」で検索) は、両方のループを並列化する場合のバージョン 2.5 の回避策にも関連しますが、上で引用したバージョン 2.5 の仕様は非常に明示的です (セクションの不適合例を参照) A.35).
他のヒント
あなたは(omp_set_nested(1)
コールの後に)ネストされたOMPパラレルFORSを使用するので試すことができ、それらはすべてのOpenMPの実装ではサポートされません。
だから私はいくつかの2Dグリッドを作成し、(固定4x4のスレッドグリッドの一例)のために、単一のグリッド上のすべてのスレッドを起動すると思います:
#pragma omp parallel for
for(k = 0; k < 16; k++)
{
int i,j,i_min,j_min,i_max,j_max;
i_min=(k/4) * (dimension/4);
i_max=(k/4 + 1) * (dimension/4);
j_min=(k%4) * (dimension/4);
j_max=(k%4 + 1) * (dimension/4);
for(i=i_min;i<i_max;i++)
for(j=j_min;j<j_max;j++)
f(i,j);
}