いくつかの点で、これは宿題の問題のように思えますが、私はそれを人々のためにしたくありません。一方で、上記の答えは完全に正確ではなく、修正する必要があると思います。
まず、この例では、共有句とプライベート句の両方は必要ありませんが、使用すべきではないというコンラッドには同意しません。コードを並列化する人々の最も一般的な問題の1つは、変数がどのように使用されているかを理解するのに時間がかからないことです。共有変数を民営化および/または保護しないことは、私が目にする問題の最大数を説明します。変数がどのように使用されているかを調べ、それらを適切な共有、プライベートなどの句に入れるという演習を行うことで、問題の数を大幅に減らすことができます。
バリアに関する質問については、2番目のループで計算された値(a)が使用されないため、最初のループにnowait句を含めることができます。2番目のループは、値が計算される前に計算された値(c)が使用されない場合(つまり、依存関係がない場合)にのみnowait句を持つことができます。元のサンプルコードでは、2番目のループには待機がありませんが、3番目のループの前に明示的なバリアがあります。教授が明示的なバリアの使用を示しようとしていたので、これは問題ありません-2番目のループでnowaitを省略すると、明示的なバリアが冗長になります(ループの最後に暗黙的なバリアがあるため)。
一方、2番目のループでの待機と明示的なバリアはまったく必要ない場合があります。OpenMP V3.0仕様の前は、多くの人が、仕様で明確にされていない何かが真実であると想定していました。OpenMP V3.0仕様では、セクション2.5.1ループ構成、表2-1スケジュール句の種類の値、静的(スケジュール)に以下が追加されました。
静的スケジュールの準拠実装では、次の条件が満たされる場合、スレッドへの論理反復数の同じ割り当てが2つのループ領域で使用されるようにする必要があります:1)両方のループ領域のループ反復数が同じである2)両方のループ領域同じchunk_sizeの値が指定されているか、両方のループ領域にchunk_sizeが指定されていない、および3)両方のループ領域が同じ並列領域にバインドされている。このような2つのループでの同じ論理反復間のデータ依存性が満たされることが保証され、nowait句を安全に使用できます(例については、170ページのセクションA.9を参照してください)。
この例では、どのループにもスケジュールが表示されていないため、これが成立する場合と成立しない場合があります。その理由は、デフォルトのスケジュールは実装によって定義されており、ほとんどの実装は現在デフォルトのスケジュールを静的に定義していますが、それを保証するものではないためです。教授が3つのループすべてにチャンクサイズのないスケジュールタイプの静的を設定した場合、1番目と2番目のループでnowaitを使用でき、2番目と3番目のループの間に(暗黙的または明示的な)バリアは必要ありません。まったく。
次に、3番目のループと、待機と削減についての質問に進みます。Michyが指摘したように、OpenMP仕様では、両方(reductionとnowait)を指定できます。ただし、削減を完了するために同期が必要ないというのは事実ではありません。この例では、(3番目のループの終わりにある)暗黙のバリアをnowaitで削除できます。これは、並列領域の暗黙のバリアに遭遇する前に、削減(合計)が使用されていないためです。
OpenMP V3.0仕様のセクション2.9.3.6削減条項を見ると、次のことがわかります。
nowaitが使用されていない場合、削減計算は構成の最後で完了します。ただし、nowaitも適用される構成でreduction句を使用すると、元のリストアイテムにアクセスすると競合が発生するため、すべてのスレッドがすべての反復を実行した後に同期が確実に発生しない限り、不特定の影響があります。またはセクションが構成され、削減計算が完了して、そのリスト項目の計算値が格納されます。これは、バリア同期によって最も簡単に保証できます。
つまり、3番目のループの後に並列領域で合計変数を使用する場合は、使用する前にバリア(暗黙的または明示的)が必要になります。例が今立っているように、それは正しいです。