これは技術的には不適切に定義されたプログラムです。
すべてではありませんがほとんど (たとえば、G80 はサポートしていません)、NVIDIA GPU はこの方法で早期終了をサポートします。これは、ハードウェアが各ブロックのアクティブ スレッド カウントを維持し、このカウントがブロックの初期スレッド カウントではなくバリア同期に使用されるためです。 .
したがって、__syncthreads()
コード内の に達すると、ハードウェアは既に返されたスレッドを待機せず、プログラムはデッドロックなしで実行されます。
このスタイルのより一般的な用途は次のとおりです。
__global__ void foo(int n, ...) {
int idx = threadIdx.x + blockIdx.x * blockDim.x;
if (idx >= n) return;
... // do some computation with remaining threads
}
重要な注意: バリア カウントは、スレッドごとではなく、ワープごとに更新されます (こちらを参照)。そのため、たとえば、少数 (またはゼロ) のスレッドのみが早期に返される場合があります。これは、バリア カウントがデクリメントされないことを意味します。ただし、各ワープから少なくとも 1 つのスレッドがバリアに到達する限り、デッドロックは発生しません。
したがって、一般に、バリアは慎重に使用する必要があります。しかし具体的には、このような (単純な) 早期終了パターンは機能します。
編集:あなたの特定のケースのために。
反復 Idx==36: 2 つのアクティブなワープがあるため、バリアの終了カウントは 64 です。ワープ 0 からのすべてのスレッドがバリアに到達し、カウントが 0 から 32 に増加します。ワープ 1 からの 4 つのスレッドがバリアに到達し、カウントが 32 から 64 に増加し、ワープ 0 と1体が結界から解放される。上記のリンクを読んで、なぜこれが起こるのかを理解してください。
反復 Idx==18: 1 つのアクティブなワープなので、バリア出口カウントは 32 です。ワープ 0 からの 18 スレッドがバリアに到達し、カウントが 0 から 32 に増加します。バリアが満たされ、ワープ 0 が解放されます。
等...