1

私は OpenMP を初めて使用し、Microsoft Visual Studio 2010 に標準で付属している OpenMP 2.0 について読んだことから、グローバル変数は並列プログラミングで使用すると面倒でエラーが発生しやすいと見なされます。グローバル変数と静的グローバル変数を効率的に処理する方法をほとんど見つけていないか、まったく知らないので、私もこの感覚を採用しています。

実行されるコードのスニペットがありますが、並列ブロックで作成されたローカル変数のために、探している答えが得られません。1つの回答ではなく、8つの異なるプリントアウトを取得します(PCにスレッドがいくつあるかのため)。並列ブロックで作成されたローカル変数「リスト」が原因であることはわかっていますが、「リスト」変数を移動してグローバル変数にすると、このコードは実行されません。実際にはコードは実行されますが、答えが返ってきません。これは、グローバルな「リスト」変数を使用するように変更したいサンプル コードです。

#pragma omp parallel
{
    vector<int> list;
#pragma  omp for
    for(int i = 0; i < 50000; i++) 
    {
        list.push_back(i);
    }
    cout << list.size() << endl;
}

出力:

6250
6250
6250
6250
6250
6250
6250
6250

合計すると 50000 になりますが、50000 の答えは 1 つではなく、分割されています。

解決:

    vector<int> list;
    #pragma omp parallel
{
    #pragma  omp for
    for(int i = 0; i < 50000; i++) 
    {
        cout << i << endl;
    #pragma omp critical
        {
            list.push_back(i);
        }
    }
}
cout << list.size() << endl;
4

2 に答える 2

1

MSDN ドキュメントによると、並列句

並列領域を定義します。これは、複数のスレッドによって並列に実行されるコードです。

また、リスト変数はこのセクション内で宣言されているため、すべてのスレッドが独自のリストを持ちます。

一方、for プラグマ

並列領域内の for ループで実行される作業をスレッド間で分割します。

したがって、50000 回の反復はスレッド間で分割されますが、各スレッドには独自のリストがあります。あなたがやろうとしていることは、次の方法で達成できると思います。

  1. 「並列」セクションの外でリスト定義を取得します。
  2. list.push_back ステートメントをクリティカル セクションで保護します。

これを試して:

vector<int> list;
#pragma omp parallel
{
#pragma  omp for
    for(int i = 0; i < 50000; i++) 
    {
#pragma omp critical
        {
            list.push_back(i);
        }
    }
}
cout << list.size() << endl;

この場合、クリティカル セクションで競合が発生するため、OpenMP による高速化は必要ないと思います。これに対するより高速な解決策 (要素の順序を気にしない場合) は、すべてのスレッドが独自のリストを持ち、ループが終了した後にそれらのリストをマージすることです。この場合、std::vector の代わりに std::list を使用した実装はよりきれいに見えます (配列をコピーする必要がないため)。

一部のアプリはメモリ バウンドであり、コンピューティング バウンドではありません。結論: OpenMP から実際にスピードアップが得られるかどうかを確認してください。

于 2012-12-26T04:03:49.487 に答える
0

ここで最初のプラグマが必要なのはなぜですか? (#pragma omp parallel)。それが問題だと思います。

于 2012-12-26T03:57:27.177 に答える