我是CUDA的初学者。我这里有一个由2个线程执行的内核。所有线程都应将结果保存到共享变量中。完成所有三个后,sum
的结果应为12,但我得到6!
__global__ void kernel (..)
{
int i=blockDim.x*blockIdx.x+threadIdx.x;
__shared__ double sum;
...
if(i==0)
sum=0.0;
__syncthreads();
if(i<=1)
sum+= 2.0*3.0;
__syncthreads();
//sum should be 12 here, but I get 6. Why?
}
通过
调用test<<<1,2>>>(..);
答案 0 :(得分:7)
您的代码中存在内存竞争。这样:
sum+= 2.0*3.0;
可能允许多个线程同时累积到总和。在您的示例中,两个线程都试图同时加载并存储在同一地址。这是CUDA中未定义的行为。
避免此问题的常用方法是重新设计算法。只是没有多个线程写入相同的内存位置。有一个非常广泛描述的共享内存减少技术,您可以使用它来累积共享内存数组的总和而无需内存竞争。
或者,存在可用于串行化存储器访问的原子存储器访问原语。你的例子是双精度浮点,我很确定没有内在的原子添加函数。编程指南包括用于双精度的user space atomic add的示例。取决于您的硬件,它可能在共享内存变量上可用,也可能不可用,因为64位共享内存原子操作仅在计算能力2.x和3.x设备上受支持。在任何情况下,都应该谨慎使用原子内存操作,因为序列化内存访问会大大降低性能。