1. 函数定义与作用

atomicAdd是CUDA提供的原子操作函数,用于在‌全局内存‌或‌共享内存‌中实现‌线程安全的加法操作‌。其核心特性包括:

  • 原子性‌:确保多线程并发访问时,加法操作不会被中断。
  • 返回值‌:返回操作前内存地址的原始值。
  • 支持数据类型‌:包括intunsigned intunsigned long longfloatdouble(需特定计算能力支持)。

2. 函数原型

cppCopy Codeint atomicAdd(int* address, int val);
unsigned int atomicAdd(unsigned int* address, unsigned int val);
float atomicAdd(float* address, float val);  // 计算能力≥6.x支持
double atomicAdd(double* address, double val);  // 计算能力≥6.x支持
  • ‌参数:
    • address:目标内存地址(全局或共享内存)。
    • val:要相加的值。
  • 返回值‌:操作前的内存值。

3. 工作原理

  1. 读取旧值‌:从address读取当前值(记为old)。
  2. 计算新值‌:执行new = old + val
  3. 写入并返回‌:将new写入address,并返回old

示例‌:

cppCopy Codeint a = 0;
int old = atomicAdd(&a, 1);  // a变为1,old为0

4. 典型应用场景

‌**(1) 并行累加统计**‌

统计数组中某值的出现次数(避免多线程竞争):

cppCopy Code__global__ void count_zeros(int* counter, char* data, int size) {
    int idx = threadIdx.x + blockIdx.x * blockDim.x;
    if (idx < size && data[idx] == 0) {
        atomicAdd(counter, 1);  // 原子递增
    }
}
‌**(2) 向量元素累加**‌

实现向量加法时保护共享变量:

cppCopy Code__global__ void vector_add(int* a, int* b, int* c, int n) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if (i < n) {
        atomicAdd(&c[i], a[i] + b[i]);  // 原子更新结果
    }
}

5. 性能注意事项

  • 开销较大‌:原子操作会序列化线程访问,可能成为性能瓶颈。
  • ‌优化策略:
    • 优先使用‌块内共享内存‌局部归约,再全局原子操作。
    • 减少原子操作的调用频率(如合并多次加法)。

6. 常见错误

  • 数据类型不匹配‌:如对float使用int版本函数(需检查计算能力)。
  • 非原子竞争‌:未使用原子操作导致结果错误(如直接counter[value]++)。

7. 扩展知识

  • 作用域控制‌:CUDA 12.0+支持_system_block等后缀,限定原子操作的作用范围。
  • 其他原子函数‌:如atomicSubatomicExch等,适用于不同场景。

如需验证设备支持的数据类型,可通过cudaGetDeviceProperties查询计算能力。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐