以原子方式在共享内存中编写结构

时间:2015-12-11 20:20:20

标签: cuda gpgpu nvcc

对于访问结构,nvcc生成一个代码,用于逐字段读取/写入结构。有这个结构:

typedef struct cache_s {
    int tag;
    TYPE data;
} cache_t;

生成以下PTX代码以将此类型的变量写入共享内存:

st.shared.f64   [%rd1+8], %fd53;
st.shared.u32   [%rd1], %r33;

这会在程序执行中引发逻辑错误。如果线程块的两个并发线程在相同的共享存储器地址处写回不同的值,则来自不同结构的字段可能混淆。 CUDA编程指南声明:

  

如果由warp执行的非原子指令写入相同的指令   多个线程的全局或共享内存中的位置   warp,发生的序列化写入次数   位置取决于设备的计算能力(请参阅   计算能力2.x,计算能力3.x和计算能力   5.x),以及哪个线程执行最终写操作是未定义的。

由此,我希望其中一个线程写出它的完整结构(整个字段在一起),我不希望混合字段(来自不同的写入)形成一个未定义的值。有没有办法强制nvcc生成我期望的代码?

更多信息:

NVCC版本:7.5

1 个答案:

答案 0 :(得分:2)

  

这会在程序执行中引发逻辑错误。如果线程块的两个并发线程在同一共享内存地址处写回不同的值,则来自不同结构的字段可能会混淆。

如果你需要从块中的一个线程获得完整的结果,同时丢弃来自其他线程的结果,只需要一个线程(线程0通常用于此)写出其结果并让其余线程跳过写:

__global__ void mykernel(...)
{
    ...
    if (!threadIdx.x) {
        // store the struct
    }
}
  

有没有办法强制nvcc生成我期望的代码?

您希望NVCC生成一条指令,对任意大小的完整结构进行原子写入。没有这样的指令,所以,不,你不能让NVCC生成代码。

  

我认为在共享内存上使用原子锁是一种解决方法,但这是一个糟糕的解决方案。有更好的解决方案吗?

我们无法告诉您什么是更好的解决方案,因为您没有告诉我们您尝试解决的问题是什么。在CUDA中,原子操作通常仅用于在读 - 修改 - 写操作期间锁定单个32位或64位字,因此不适合保护完整的结构。

有并行操作,有时称为并行原语,例如“reduce”和“scan”,它们允许在不锁定的情况下解决许多类型的问题。例如,您可能首先启动一个内核,其中每个线程将其结果写入一个单独的位置,然后启动一个执行并行reduce的新内核来选择您需要的结果。