我有一个CUDA程序的代码:
#include <stdio.h>
#define NUM_BLOCKS 4
#define THREADS_PER_BLOCK 4
__global__ void hello()
{
printf("Hello. I'm a thread %d in block %d\n", threadIdx.x, blockIdx.x);
}
int main(int argc,char **argv)
{
// launch the kernel
hello<<<NUM_BLOCKS, THREADS_PER_BLOCK>>>();
// force the printf()s to flush
cudaDeviceSynchronize();
return 0;
}
其中每个帖子都会打印其threadIdx.x
和blockIdx.x
。该计划的一个可能输出是:
Hello. I'm a thread 0 in block 0
Hello. I'm a thread 1 in block 0
Hello. I'm a thread 2 in block 0
Hello. I'm a thread 3 in block 0
Hello. I'm a thread 0 in block 2
Hello. I'm a thread 1 in block 2
Hello. I'm a thread 2 in block 2
Hello. I'm a thread 3 in block 2
Hello. I'm a thread 0 in block 3
Hello. I'm a thread 1 in block 3
Hello. I'm a thread 2 in block 3
Hello. I'm a thread 3 in block 3
Hello. I'm a thread 0 in block 1
Hello. I'm a thread 1 in block 1
Hello. I'm a thread 2 in block 1
Hello. I'm a thread 3 in block 1
多次运行程序我得到了类似的结果,除了块顺序是随机的。例如,在上面的输出中我们有这个块顺序0,2,3,1。再次运行问题我得到1,2,3,0。这是预期的。但是,每个块中的线程顺序始终为0,1,2,3。为什么会这样?我以为它也是随机的。
我试图更改我的代码以强制每个块中的线程0花费更长的时间来执行。我是这样做的:
__global__ void hello()
{
if (threadIdx.x == 0)
{
int k = 0;
for ( int i = 0; i < 1000000; i++ )
{
k = k + 1;
}
}
printf("Hello. I'm a thread %d in block %d\n", threadIdx.x, blockIdx.x);
}
我希望线程顺序为1,2,3,0。但是,我得到的结果与我上面显示的结果类似,其中线程顺序始终为0,1,2,3。为什么会发生这种情况?
答案 0 :(得分:2)
但是,每个块中的线程顺序始终为0,1,2,3。为什么会这样?我以为它也是随机的
每个块有4个线程,每个块只启动一个 warp 。 warp是CUDA中的执行(以及调度和资源分配)的单位,而不是线程。目前,warp由32个线程组成。
这意味着每个块的所有4个线程(因为在这种情况下没有条件行为)正在 lockstep 中执行。当他们到达printf
函数调用时,他们都在同一行代码中执行对该函数的调用,在锁步中。
所以问题就变成了,在这种情况下,CUDA运行时如何调度这些&#34;同时&#34;功能调用?这个问题的答案没有具体说明,但并不是随机的#34;。因此,在warp中操作的调度顺序不会在不同的运行中发生变化是合理的。
如果启动足够的线程来为每个块创建多个warp,并且可能还包含一些其他代码来分散和/或随机化&#34;经线之间的行为,你应该能够看到printf
操作来自于&#34;随机&#34;中发生的单独扭曲。顺序。
答案 1 :(得分:1)
要回答问题的第二部分,当控制流在if
语句处发散时,threadIdx.x != 0
只是在if
语句之后等待收敛点的线程。在线程0完成printf
块之前,它们不会继续if
语句。