Answers:
例如,如果一个GPU设备具有4个多处理单元,并且每个单元可以运行768个线程:那么在给定的时刻,真正并行运行的线程将不超过4 * 768(如果您计划更多的线程,它们将在等待轮到他们了)。
线程按块组织。块由多处理单元执行。可以使用1Dimension(x),2Dimensions(x,y)或3Dim索引(x,y,z)来标识(索引)块的线程,但在任何情况下,对于我们的示例,x y z <= 768(适用其他限制)到x,y,z,请参阅指南和您的设备功能)。
显然,如果您需要多个4 * 768线程,则需要四个以上的块。块也可以索引为1D,2D或3D。等待进入GPU的队列有很多(因为在我们的示例中,GPU有4个多处理器,并且只有4个块正在同时执行)。
假设我们要一个线程处理一个像素(i,j)。
我们可以每个使用64个线程的块。然后我们需要512 * 512/64 = 4096块(因此要具有512x512线程= 4096 * 64)
通常将具有blockDim = 8 x 8(每个块64个线程)的2D块中的线程组织起来(使索引索引更容易)。我更喜欢将其称为threadsPerBlock。
dim3 threadsPerBlock(8, 8); // 64 threads
和2D gridDim = 64 x 64块(需要4096个块)。我更喜欢将其称为numBlocks。
dim3 numBlocks(imageWidth/threadsPerBlock.x, /* for instance 512/8 = 64*/
imageHeight/threadsPerBlock.y);
内核是这样启动的:
myKernel <<<numBlocks,threadsPerBlock>>>( /* params for the kernel function */ );
最后:将会出现“ 4096个块的队列”之类的东西,其中一个块正等待分配给GPU的多处理器之一,以使其64个线程得以执行。
在内核中,线程要处理的像素(i,j)的计算方式如下:
uint i = (blockIdx.x * blockDim.x) + threadIdx.x;
uint j = (blockIdx.y * blockDim.y) + threadIdx.y;
假设9800GT GPU:
https://www.tutorialspoint.com/cuda/cuda_threads.htm
一个块的活动线程数不能超过512,因此__syncthreads
只能同步有限数量的线程。即如果您使用600个线程执行以下操作:
func1();
__syncthreads();
func2();
__syncthreads();
那么内核必须运行两次,执行顺序为:
注意:
要点是__syncthreads
块级操作,它不同步所有线程。
我不确定__syncthreads
可以同步的确切线程数,因为您可以创建一个具有512个以上线程的块,并让warp处理调度。据我了解,更准确地说:func1 至少在前512个线程中执行。
在编辑此答案之前(早在2010年),我测量了14x8x32线程使用进行了同步__syncthreads
。
如果有人再测试一次以获得更准确的信息,我将不胜感激。
__syncthreads
是一个块范围的操作,它实际上并未同步所有线程,这对CUDA学习者来说是个麻烦。因此,我根据您提供给我的信息更新了答案。我真的很感激。