原子操作
SIMT编程模型中,一个Grid由多个Thread Block组成,每个Thread Block又包含多个Thread。不同Thread可以并发访问同一段Global Memory或Unified Buffer(UB)。当多个线程同时对同一地址执行读-改-写操作时,如果没有同步保护,可能出现数据竞争,导致最终结果不符合预期。
原子操作用于保证同一地址上的一次读-改-写过程不可被其他线程打断。典型场景包括计数、状态抢占、直方图统计和并行归约等。
基本语义
原子操作保证的是单次内存更新的原子性。例如多个线程同时对同一个计数器执行asc_atomic_add时,每次加法都会以原子方式完成,不会出现多个线程读取同一个旧值后覆盖彼此结果的问题。
原子操作不保证多个线程到达该原子操作的先后顺序,也不是线程同步屏障。多个Thread、Warp或Thread Block同时访问同一地址时,硬件会对这些原子请求进行串行化处理,但串行化顺序通常不由程序指定。
Ascend C SIMT提供asc_atomic_add、asc_atomic_sub、asc_atomic_cas等原子操作接口,可用于Global Memory或UB中的数据更新。不同接口支持的数据类型、访问空间和返回值约束不同,详细说明请参见原子操作接口。
使用建议
- 仅在确实存在并发写同一地址且需要保证更新不丢失时使用原子操作。
- 不要将原子操作等同于线程同步;需要线程到达同一执行点时,应使用同步接口。
- 避免大量线程频繁原子更新同一个Global Memory地址,必要时先在Thread Block内做局部聚合。
- 不要依赖原子操作返回值表达稳定的线程执行顺序。