__global__ void substract(float *A, float *B, float *res, int *n)
{
int size = *n;
int tid = threadIdx.x + blockIdx.x*blockDim.x;
while (tid < size)
{
res[tid] = A[tid] - B[tid];
tid += blockDim.x * gridDim.x;
}
}
int function(...) {
int threadsPerBlock = 256;
int blocks = (n+threadsPerBlock-1)/threadsPerBlock;
int blocksPerGrid = 32<blocks ? 32 : blocks;
.
.
.
substract<<<blocksPerGrid, threadsPerBlock>>>(A, B, res, n);
.
.
.
}
因此,我编写了这段代码,其中包含一个数组A
,该数组表示大小为n
x n
的矩阵,另一个数组B
表示大小为{ {1}},我从另一个中减去一个。假设此数组的大小为1000x1000。我是通过遵循多个cuda指南中的示例来编写的,但我不明白我们为什么需要此部分:n
由于它将永远无法用作数组id元素,因此它将始终大于或等于1024,并且我的数组仅具有0-999 id,对我来说似乎没有用,但是如果没有它,我的程序崩溃,屏幕将变黑几秒钟后,它又返回,我弹出驱动程序已恢复的提示。因此,我试图理解为什么我不能只使用tid += blockDim.x * gridDim.x;
遍历整个数组。我在tid = threadIdx.x + blockIdx.x*blockDim.x;
循环之前打印了所有tid
,由于它不能依靠while
来计算内部的任何内容,因此它似乎一直以0到1024的顺序随机排列。我猜我的数组边界。
答案 0 :(得分:1)
如果您的数组大小等于或小于网格大小,则在这种情况下,网格跨度循环不会提供太多好处。当数组大小大于网格大小时,或者当您要编写一个可以灵活处理任意数组大小而无需调整网格大小的内核时,此功能特别有用。
但是,如果您的数组大小小于或等于网格大小,可能仍需要网格跨度附加代码。如果仔细考虑一下while循环,其原因将变得显而易见:需要执行此加法操作才能使while循环在所有线程上终止。
假设您的数组大小为1024,并且它等于1024个线程的网格大小(是否全部在一个块中;无所谓)。
最初,您的线程将具有0-1023的tid
索引。这些值均不会导致while循环终止。如果while循环永远不会终止,则您的内核将永远挂起并运行,直到或除非您遇到内核超时(这是您所看到的)。
但是使用加法语句,在第一次while循环迭代之后,每个线程的tid
值等于或大于1024,这将导致while循环对于所有线程终止(假设size
是1024或更少)。