0

OpenMP がネストされたループでどのように機能するかを理解するのに問題があります。助けてください!

並行して実行する次のコードを取得しました。

#pragma omp parallel private(i)
{
for(i=0; i<n; i++)
{
    #pragma omp for
    for(j=0; j<n; j++)
    {
        if(asubsref(seed,j) > 0)
            asubsref(bin,j) = asubsref(bin,j) + 1;
    }
    #pragma omp for
    for(j=0; j<n; j++)
        asubsref(seed,j) = asubsref(seed,j) - asubsref(w,i);
}
}

ただし、このコードがどのように機能するかはよくわかりません (運が良かっただけです)。これが私がそれがしていると思うことです...

そのfor(i=0; i<n; i++)ため、異なるスレッドに分割され、並行して実行されます。iは であると宣言されているためprivate、ループの各インスタンスは「サンドボックス化」されています。つまり、変更jはそのスレッドに残ります (少なくともすべてのスレッドが完了するまで?)。宣言しない#pragma omp forとコードが破損するため、混乱しています...なぜそうなのかわかりません。

誰かがこのコードが何をしているかを説明してくれたら、とても感謝しています! ありがとうございました!

4

1 に答える 1

2

これは、複数の並列領域への出入りのオーバーヘッドを削減するために通常行うことです。質問のコードを次の同等のコードと比較してください。

for (i=0; i<n; i++)
{
    #pragma omp parallel for
    for (j=0; j<n; j++)
    {
        if (asubsref(seed,j) > 0)
            asubsref(bin,j) = asubsref(bin,j) + 1;
    }
    #pragma omp parallel for
    for (j=0; j<n; j++)
        asubsref(seed,j) = asubsref(seed,j) - asubsref(w,i);
}

外側のループをi n何度も実行します。外側のループの各反復では、2 つの並列ループが で実行され、反復がスレッド間jで分割されます。nここでの問題は、内部に 2 つの並列領域があり、それぞれがn何度もアクティブになっていることです。これにより、値の特定の間隔に大きなオーバーヘッドが追加される可能性がありますn(実際の間隔は多くの要因に依存します)。

オーバーヘッドを削減するために、コード全体を並列領域内に配置します。したがって、各スレッドは外側のループのすべての反復を実行し、内側の反復はスレッド間で分割されます。ワークシェアリング構造を削除すると、内側のループがスレッド間で分散されなくなります。代わりに、各スレッドは外部反復内部反復の両方の全範囲を実行するため、たとえば、 1 回だけではなく、asubsref(bin,j)最大回数だけインクリメントされますnum_threads(なぜ「最大」なのか? ヒント: 保護されていない同時データ アクセス)。

ほとんどの場合、並列構造内で外側のループを実行する場合、異なるスレッドが同じ反復で刻み続けることを望みます。これは、ループ本体の最後にあるバリアによって実現できます。

#pragma omp parallel private(i)
{
    for (i = 0; i < n; i++)
    {
        ...
        #pragma omp barrier
    }
}

あなたの場合、forワークシェアリング構造の最後に暗黙のバリアがあるため、明示的なバリアは必要ありません。

于 2012-11-27T09:53:27.057 に答える