我有一段 CUDA 代码,其中线程在共享内存上执行原子操作。我在想,因为原子操作的结果会立即对块的其他线程可见,所以指示编译器拥有共享内存volatile
可能会很好。
所以我改变了
__global__ void CoalescedAtomicOnSharedMem(int* data, uint nElem)
{
__shared__ int smem_data[BLOCK_SIZE];
uint tid = (blockIdx.x * blockDim.x) + threadIdx.x;
for ( uint i = tid; i < nElem; i += blockDim.x*gridDim.x){
atomicAdd( smem_data+threadIdx.x, 6);
}
}
到
__global__ void volShared_CoalescedAtomicOnSharedMem(int* data, uint nElem)
{
volatile __shared__ int smem_data[BLOCK_SIZE];
uint tid = (blockIdx.x * blockDim.x) + threadIdx.x;
for ( uint i = tid; i < nElem; i += blockDim.x*gridDim.x){
atomicAdd( smem_data+threadIdx.x, 6);
}
}
编译时错误发生以上变化:
error: no instance of overloaded function "atomicAdd" matches the argument list
argument types are: (volatile int *, int)
为什么不支持volatile
地址作为原子操作的参数?是因为编译器一旦识别出对它的原子操作就已经将共享内存视为易失性了吗?
答案 0 :(得分:4)
volatile
限定符的定义在the programming guide中给出。它指示编译器始终为该访问生成读取或写入,并且永远不会优化&#34;它进入寄存器或其他一些优化。
由于原子操作是guaranteed to act on actual memory locations(共享或全局),因此两者的组合是不必要的。因此,未提供原型为volatile
限定符的原型函数版本。
如果您的内存位置已声明为volatile
,则在将地址传递给原子函数时,只需将其强制转换为相应的非volatile
类型。行为将符合预期。(example)
因此,在此条件下,原子操作可以在指定为volatile
的位置上运行。
您在代码中的某处使用atomics访问特定位置的简单事实并不意味着编译器会将其他访问视为隐式volatile
。如果您在其他地方需要volatile
行为,请明确声明。
答案 1 :(得分:-1)
上一张海报已正确识别问题:这里没有定义带有易失性参数的atomicAdd函数。
关于我为什么会这样的问题,我的猜测是你的图书馆开发人员只是省略了那个界面。想象一下,volatile,const和可能参数的所有组合以及潜在接口的数量开始爆炸。
Why isn't a volatile address supported as an argument for atomic operations?
原子操作不是C / C ++的一部分。在您的情况下,它们是在一个可能用汇编语言实现的库中实现的。
Is it because compiler already treats the shared memory as volatile as soon as it identifies there's going to be atomic operations on it?
不,这是图书馆作家定义功能界面的方式