从技术上讲,这是一个定义不明确的程序。
大多数但不是全部(例如 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
}
重要提示:屏障计数是按经纱更新的(请参阅此处),而不是按线程更新。因此,您可能会遇到这样的情况,例如,只有少数(或零个)线程提前返回。这意味着屏障计数不会减少。但是,只要每个 warp 中至少有一个线程到达屏障,它就不会死锁。
所以一般来说,你需要谨慎使用屏障。但具体来说,像这样的(简单)提前退出模式确实有效。
编辑:针对您的具体情况。
迭代Idx == 36:2个活动warp,因此屏障退出计数为64。来自warp 0的所有线程都到达屏障,将计数从0增加到32。来自warp 1的4个线程到达屏障,将计数从32增加到64,并且warp 0和1 从屏障中释放出来。阅读上面的链接以了解为什么会发生这种情况。
迭代 Idx==18:1 个活动 warp,因此屏障退出计数为 32。来自 warp 0 的 18 个线程到达屏障,计数从 0 增加到 32。满足屏障并释放 warp 0。
ETC...