我正在使用CUDA提供的编程指南自学CUDA。为了实践,我创建了一个简单的内核,用于确定数组的最大值并将其返回给CPU:
__global__ void getTheMaximum(float* myArrayFromCPU, float* returnedMaximum) {
// Store my current value in shared memory.
extern __shared__ float sharedData[];
sharedData[threadIdx.x] = myArrayFromCPU[threadIdx.x];
// Iteratively calculate the maximum.
int halfScan = blockDim.x / 2;
while (halfScan > 0 && threadIdx.x < halfScan) {
if (sharedData[threadIdx.x] < sharedData[threadIdx.x + halfScan]) {
sharedData[threadIdx.x] = sharedData[threadIdx.x + halfScan];
}
halfScan = halfScan / 2;
}
// Put maximum value in global memory for later return to CPU.
returnedMaximum[0] = sharedData[0];
}
myArrayFromCPU
是一个大小为1024的浮点值数组。returnedMaximum
是一个包含单个项目的简单数组:计算出的最大值。
我对这个算法的想法是,它会迭代地确定最大值,因为它会将块大小的一半减去当前值。
但是,当我运行此代码时,输出的输出不可靠。返回的最大值会有所不同。这是为什么?单个算法如何每次都产生不同的值?
更新
我也只是在一个块上运行。我通过设置X = 1024的1维块大小来保证这一点。
答案 0 :(得分:2)
不能保证整个块的所有线程都在同一时刻执行。这保证你只有一个warp(32个线程组)。
为了避免块内的并发危险 - 您可以使用__syncthreads()
内部函数来停止到达它的线程,直到所有线程到达该点。
请注意,您不应将__syncthreads()
放在分支代码中,否则您无法保证所有线程都能统一到达该位置。
尝试以下循环:
__syncthreads();
while (halfScan > 0) {
if (threadIdx.x < halfScan) {
if (sharedData[threadIdx.x] < sharedData[threadIdx.x + halfScan]) {
sharedData[threadIdx.x] = sharedData[threadIdx.x + halfScan];
}
}
__syncthreads();
halfScan = halfScan / 2;
}
请注意,我从while循环中删除了条件threadIdx.x < halfScan
,因为我希望所有线程在同一位置执行__syncthreads()
且次数相同
此外,循环之前的__syncthreads()
可能有助于确保在循环开始之前myArrayFromCPU
的负载完成(对于所有线程)。