You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

CUDA原子操作的线程/块级别与块级序列化相关技术咨询

CUDA原子操作:线程级/块级区分与块级序列化解析

一、先明确:CUDA原子操作本质是线程级的

所有CUDA原子操作都是单个线程发起的操作——核心是保证"读-改-写"这一整套动作不会被其他线程打断,同一时间只有发起操作的那个线程能完成这个完整流程。不管是操作全局内存还是共享内存,原子操作的执行主体都是线程,所以本质上是线程级的。

二、搞懂"块级序列化"到底是什么

你说的"块级序列化",其实是一种跨线程块的执行阻塞现象:当多个不同线程块里的线程,同时对同一个全局内存地址执行原子操作时,GPU的全局原子处理单元没办法同时处理这些请求,只能让这些线程块里的线程排队执行——也就是一个块的线程先完成原子操作,下一个块的线程才能跟上,原本的多块并行就变成了串行,这就是所谓的"块级序列化"。

举个例子:如果10个线程块都往同一个全局变量total_sum里做atomicAdd,那这10个块的原子操作就会排队,一个接一个来,没办法并行推进,这就是块级序列化。

而如果是同一个线程块内的线程对共享内存做原子操作,因为共享内存是每个块私有的,而且SM(流多处理器)有本地的原子处理单元,同一SM内的线程操作共享内存原子时,只会有线程级的排队,不会影响其他块的并行,也就不会触发块级序列化。

三、什么时候会出现块级序列化的原子操作?

主要有两种典型场景:

  • 多个线程块的线程同时操作同一个全局内存地址(比如多块累加同一个全局变量);
  • 全局原子单元成为性能瓶颈,来自不同块的原子请求积压,只能串行处理,此时就表现为块级的序列化。

四、你的代码会不会触发块级序列化?

先看你的代码(顺便提个小问题,共享内存的初始化写法不对,后面会纠正):

__global__ void sum (int *input){ 
    if ( threadIdx.x == 0) 
        __shared__ int result = 0; 
    __syncthreads(); 
    atomicAdd(result,input[threadIdx.x+blockDim.x*blockId.x]); 
}

首先纠正个小错误:__shared__变量不能在if分支里声明初始化,正确的写法应该是先声明共享变量,再由线程0初始化后同步:

__shared__ int result;
if (threadIdx.x == 0) result = 0;
__syncthreads();

回到块级序列化的问题:这里的atomicAdd是对**当前线程块私有的共享内存变量result**执行的。每个线程块的result都是独立的,不同块的线程根本不会碰彼此的result,所以完全没有跨块的内存竞争。

结论是:这段代码不会发生块级序列化。各个线程块的原子操作各自在自己的共享内存里完成,彼此并行不干扰,只有同一个块内的线程会有线程级的原子排队,但这和块级序列化完全是两回事。


内容的提问来源于stack exchange,提问作者ClaudiaBordone

火山引擎 最新活动