更新:while()
以下の条件はコンパイラによって最適化されるため、両方のスレッドは単に条件をスキップし、-O0
フラグを付けても CS に入ります。コンパイラがこれを行っている理由を誰かが知っていますか? ちなみに、グローバル変数を宣言するvolatile
と、奇妙な理由でプログラムがハングアップします...
CUDA プログラミング ガイドを読みましたが、 CUDAがグローバル メモリに関してメモリの一貫性をどのように処理するかについては、まだ少し不明です。(これはメモリ階層とは異なります) 基本的には、順次整合性を崩そうとするテストを実行しています。私が使用しているアルゴリズムは、カーネル関数内の2 つのスレッド間の相互排除のための Peterson のアルゴリズムです。
flag[threadIdx.x] = 1; // both these are global
turn = 1-threadIdx.x;
while(flag[1-threadIdx.x] == 1 && turn == (1- threadIdx.x));
shared_gloabl_variable_x ++;
flag[threadIdx.x] = 0;
これはかなり簡単です。各スレッドは、フラグを 1 に設定し、別のスレッドに順番を与えることで、クリティカル セクションを要求します。の評価時にwhile()
、他のスレッドがそのフラグを設定していない場合、要求元のスレッドは安全にクリティカル セクションに入ることができます。このアプローチの微妙な問題は、コンパイラが書き込みの順序を変更して、 への書き込みが へturn
の書き込みの前に実行される場合flag
です。これが発生すると、両方のスレッドが同時に CS で終了します。ほとんどのプロセッサは順次整合性を実装していないため、通常の Pthreads でこれを証明するのはかなり簡単です。しかし、GPU はどうでしょうか?
これらのスレッドは両方とも同じワープになります。そして、ステートメントをロックステップ モードで実行します。しかし、それらがturn
変数に到達すると、同じ変数に書き込まれるため、ワープ内の実行はシリアル化されます (順序は関係ありません)。この時点で、勝ったスレッドは while 条件に進みますか、それとも他のスレッドが書き込みを終了するのを待って、両方がwhile()
同時に評価できるようにしますか? パスは で再び分岐しwhile()
ます。これは、そのうちの 1 つだけが勝ち、もう 1 つが待機するためです。
コードを実行した後、一貫して SC を壊すようになりました。私が読んだ値は常に 1 です。これは、両方のスレッドが何らかの形で毎回 CS に入っていることを意味します。これはどのように可能ですか (GPU は命令を順番に実行します)? (注: でコンパイルした-O0
ため、コンパイラの最適化は行われず、したがって は使用されませんvolatile
)。