2

ネストされたループがあります:(LとAは完全に定義された入力です)

    #pragma omp parallel for schedule(guided) shared(L,A) \
    reduction(+:dummy)
    for (i=k+1;i<row;i++){
            for (n=0;n<k;n++){
                #pragma omp atomic
                dummy += L[i][n]*L[k][n];
                L[i][k] = (A[i][k] - dummy)/L[k][k];
            }
            dummy = 0;
    }

そしてそのシーケンシャルバージョン:

    for (i=k+1;i<row;i++){
            for (n=0;n<k;n++){
                dummy += L[i][n]*L[k][n];
                L[i][k] = (A[i][k] - dummy)/L[k][k];
            }
            dummy = 0;
    }

どちらも異なる結果をもたらします。また、パラレルバージョンはシーケンシャルバージョンよりもはるかに低速です。

何が問題を引き起こす可能性がありますか?

編集:

アトミックディレクティブによって引き起こされる問題を取り除くために、私は次のようにコードを変更しました。

#pragma omp parallel for schedule(guided) shared(L,A) \
    private(i)
    for (i=k+1;i<row;i++){
        double dummyy = 0;
        for (n=0;n<k;n++){
            dummyy += L[i][n]*L[k][n];
            L[i][k] = (A[i][k] - dummyy)/L[k][k];
        }
    }

しかし、それも問題を解決しませんでした。結果はまだ異なります。

4

3 に答える 3

2

私はOpenMPにあまり精通していませんが、計算は順序に依存しないようです。L[i][k]つまり、内側のループの結果はwhereiに書き込まれ、kは内側のループの不変条件です。これは、同じ値がk内部ループ中に上書きされ、競合状態になることを意味します。

さらに、dummy異なるスレッド間で共有されているように見えるので、プラグマパラメータが何らかの理由でそれを妨げない限り、そこにも競合状態が存在する可能性があります。

全体として、シーケンシャル実行で得られるのと同じ結果が必要な場合は、内側のループでの計算を同じシーケンシャル順序で実行する必要があるように見えます。したがって、並列化できるのは外側のループだけです。

于 2012-04-07T08:14:26.637 に答える
2

並列バージョンでは、不要な(そしておそらく有害な)アトミックディレクティブを挿入しました。dummyリダクション変数であると宣言すると、OpenMPはリダクションに干渉するスレッドを停止します。不要なディレクティブの主な影響は、コードの速度を大幅に低下させることだと思います。

結果の誤りに対処する別の答えがあるようです。dummyしかし、各外部ループの反復の最後に設定しているように見えることに気付き0ました。これは、ある種のアキュムレータとして使用しようとしている場合は奇妙に思えます。これは、reduction句が示唆していることです。dummyおそらく、内側のループ全体に縮小したいですか?

削減に問題がある場合は、こちらをお読みください

于 2012-04-07T08:19:57.940 に答える
1

n結果の違いは、ompプラグマの外部で定義されているため、スレッド間で共有される内部ループ変数に起因します。

明確化:ループ変数nは、たとえばスレッド固有である必要があるため、ompプラグマ内で宣言する必要がありますfor (int n = 0;.....)

于 2012-04-07T09:08:21.340 に答える