次に omp_prime.c のバグを修正する方法を示します。このファイルの全コードリストは、「2.1.1 omp_prime.c の全コード」にあります。
行 45 の total の read と行 46 の total への write とのデータ競合を解決するには、行 45 と 46 をクリティカルセクションに移動します。クリティカルセクションはこの 2 つの行を保護し、データ競合の発生を防ぎます。次に修正したコードを示します。
42 #pragma omp parallel for . 43 for (i = 2; i < N; i++) { 44 if ( is_prime(i) ) { #pragma omp critical { 45 primes[total] = i; 46 total++; } 47 } 48 }
1 つのクリティカルセクションを追加することで、omp_prime.c 内のほかの 2 つのデータ競合も解決されます。行 45 の prime[]
でのデータ競合だけでなく、行 46 の total でのデータ競合も解決します。4 つ目の、 行 18 の pflag[]
の read と行 21 の pflag[]
への write とのデータ競合は、不正な結果につながることはないため、実際には良性のデータ競合です。良性のデータ競合の解決は重要ではありません。
次に示すように行 45 と 46 をクリティカルセクションに移動することもできますが、この変更はプログラムの問題の解決になりません。
42 #pragma omp parallel for . 43 for (i = 2; i < N; i++) { 44 if ( is_prime(i) ) { #pragma omp critical { 45 primes[total] = i; } #pragma omp critical { 46 total++; } 47 } 48 }
スレッドが排他的ロックを使用して total へのアクセスを制御していないため、行 45 と 46 を含むこのクリティカルセクションによってデータ競合は解消されます。行 46 を含むクリティカルセクションは、total の演算値が必ず正しくなるようにします。しかし、依然としてプログラムは正しくありません。2 つのスレッドが、同じ total 値を使用して primes[]
の同じ要素を更新する可能性があります。さらに、primes[]
内の一部要素にまったく値が代入されない可能性があります。