2

来自CUDA 编程指南

unsigned int atomicInc(unsigned int* address,
                       unsigned int val);

读取位于全局或共享内存old中地址的 32 位字,计算并将结果存储回同一地址的内存中。这三个操作在一个原子事务中执行。函数返回。address((old >= val) ? 0 : (old+1))old

这很好,花花公子。但在哪里

unsigned int atomicInc(unsigned int* address);

哪个只是增加值address并返回旧值?和

void atomicInc(unsigned int* address);

它只是增加 at 的值address并且什么都不返回?

注意:当然我可以通过包装实际的 API 调用来“自己动手”,但我认为硬件的操作更简单,可能更便宜。

4

2 回答 2

3

他们没有实现简单的增加和减少操作,因为这些操作不会有更好的性能。当前架构中的每条机器代码指令占用相同的空间量,即 64 位。换句话说,指令中有完整的 32 位立即数的空间,并且由于它们具有支持添加完整 32 位值的原子指令,因此它们已经使用了晶体管。

我认为旧处理器上的专用指令incdec指令现在只是晶体管更昂贵且指令缓存很小的时代的产物,因此值得努力将指令编码为尽可能少的位。我的猜测是,在新的 CPU 上,incanddec指令是在内部根据更通用的加法函数实现的,并且主要是为了向后兼容。

于 2013-11-12T15:02:31.117 回答
1

您应该能够使用以下方法完成“简单”原子增量:

__global__ void mykernel(int *value){
  int my_old_val = atomicAdd(value, 1);
}

同样,如果您不关心返回值,这是完全可以接受的:

__global__ void mykernel(int *value){
  atomicAdd(value, 1);
}

您可以通过以下方式进行类似的原子递减:

  atomicSub(value, 1);

甚至

  atomicAdd(value, -1);

是编程指南中关于原子的部分,其中涵盖了计算能力对各种函数和数据类型的支持。

于 2013-11-12T22:00:56.877 回答