CUDA多线程写入共享变量

时间:2013-05-28 06:29:55

标签: multithreading cuda thread-safety gpu shared-memory

我是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>>>(..);

1 个答案:

答案 0 :(得分:7)

您的代码中存在内存竞争。这样:

sum+= 2.0*3.0;

可能允许多个线程同时累积到总和。在您的示例中,两个线程都试图同时加载并存储在同一地址。这是CUDA中未定义的行为。

避免此问题的常用方法是重新设计算法。只是没有多个线程写入相同的内存位置。有一个非常广泛描述的共享内存减少技术,您可以使用它来累积共享内存数组的总和而无需内存竞争。

或者,存在可用于串行化存储器访问的原子存储器访问原语。你的例子是双精度浮点,我很确定没有内在的原子添加函数。编程指南包括用于双精度的user space atomic add的示例。取决于您的硬件,它可能在共享内存变量上可用,也可能不可用,因为64位共享内存原子操作仅在计算能力2.x和3.x设备上受支持。在任何情况下,都应该谨慎使用原子内存操作,因为序列化内存访问会大大降低性能。