CUDA多线程写入共享变量

Pri*_*alj 1 multithreading cuda gpu thread-safety 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?
}
Run Code Online (Sandbox Code Playgroud)

叫做

test<<<1,2>>>(..);
Run Code Online (Sandbox Code Playgroud)

tal*_*ies 8

您的代码中存在内存竞争.这个:

sum+= 2.0*3.0;
Run Code Online (Sandbox Code Playgroud)

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

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

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