CUDAは、1つのスレッドが、あるアドレスに対して処理を行っている間に、他のスレッドに割り込まれない、排他的な処理をサポートしており、それをAtomic演算と呼ぶ。
Atomic演算を行う関数は複数ある[1]が、総和計算では atomicAdd()
を用いるとよい。
Atomic演算を活用した総和計算は次の通り。
"sum_atomic.cu"
...
__global__ gpu_sum(int *sum_dev, int *arr_dev){
int i_global = blockIdx.x * blockDim.x + threadIdx.x;
if(i_global < Narr){
atomicAdd(sum_dev, arr_dev[i_global]);
}
}
...
sum_dev
というアドレスに対して、arr_dev[i_global]
という値を足し込んでいる。
こうすることでアクセスの衝突が起こらず、正しい動作をする。
しかし、これでは逐次処理を行っているのと大差なく、高速に動作するわけではない。
sum_dev
にあるスレッドが書き込んでいる間、他のスレッドは待機を余儀なくされるからだ。
GPUの資源を活用するためにはもうひと工夫が必要だ。
[1] CUDAアトミック関数