和許多多線程並行問題一樣,CUDA也存在互斥訪問的問題,即當一個線程改變變量X,而另外一個線程在讀取變量X的值,執行原子操作類似於有一個自旋鎖,只有等X的變量在改變完成之后,才能執行讀操作,這樣可以保證每一次讀取的都是最新的值.
在kernel 程序中,做統計累加,都需要使用原子操作:atomicAdd();
原子操作很明顯的會影響程序性能,所以可以的話,盡可能避免原子操作.
CUDA原子操作API:
C.1.1 atomicAdd()
int atomicAdd(int* address, int val);
unsigned int atomicAdd(unsigned int* address,
unsigned int val);
unsigned long long int atomicAdd(unsigned long long int* address,
unsigned long long int val);
讀取位於全局或共享存儲器中地址address 處的32 位或64 位字old,計算(old + val),並將結果存儲在存儲器的同一地址中。這三項操作在一次原子事務中執行。該函數將返回old。
只有全局存儲器支持64 位字。
C.1.2 atomicSub()
int atomicSub(int* address, int val);
unsigned int atomicSub(unsigned int* address,
unsigned int val);
讀取位於全局或共享存儲器中地址address 處的32 位字old,計算(old - val),並將結果存儲在存儲器的同一地址中。這三項操作在一次原子事務中執行。該函數將返回old。
C.1.3 atomicExch()
int atomicExch(int* address, int val);
unsigned int atomicExch(unsigned int* address,
unsigned int val);
unsigned long long int atomicExch(unsigned long long int* address,
unsigned long long int val);
float atomicExch(float* address, float val);
讀取位於全局或共享存儲器中地址address 處的32 位或64 位字old,並將val 存儲在存儲器的同一地址中。這兩項操作在一次原子事務中執行。該函數將返回old。
只有全局存儲器支持64 位字。
C.1.4 atomicMin()
int atomicMin(int* address, int val);
unsigned int atomicMin(unsigned int* address,
unsigned int val);
讀取位於全局或共享存儲器中地址address 處的32 位字old,計算old 和val 的最小值,並將結果存儲在存儲器的同一地址中。這三項操作在一次原子事務中執行。該函數將返回old。
C.1.5 atomicMax()
int atomicMax(int* address, int val);
unsigned int atomicMax(unsigned int* address,
unsigned int val);
讀取位於全局或共享存儲器中地址address 處的32 位字old,計算old 和val 的最大值,並將結果存儲在存儲器的同一地址中。這三項操作在一次原子事務中執行。該函數將返回old。
C.1.6 atomicInc()
unsigned int atomicInc(unsigned int* address,
unsigned int val);
讀取位於全局或共享存儲器中地址address 處的32 位字old,計算 ((old >= val) ? 0 : (old+1)),並將結果存儲在存儲器的同一地址中。這三項操作在一次原子事務中執行。該函數將返回old。
C.1.7 atomicDec()
unsigned int atomicDec(unsigned int* address,
unsigned int val);
讀取位於全局或共享存儲器中地址address 處的32 位字old,計算 (((old == 0) | (old > val)) ? val : (old-1)),並將結果存儲在存儲器的同一地址中。這三項操作在一次原子事務中執行。該函數將返回old。
C.1.8 atomicCAS()
int atomicCAS(int* address, int compare, int val);
unsigned int atomicCAS(unsigned int* address,
unsigned int compare,
unsigned int val);
unsigned long long int atomicCAS(unsigned long long int* address,
unsigned long long int compare,
unsigned long long int val);
讀取位於全局或共享存儲器中地址address 處的32 位或64 位字old,計算 (old == compare ? val : old),並將結果存儲在存儲器的同一地址中。這三項操作在一次原子事務中執行。該函數將返回old(比較並交換)。
只有全局存儲器支持64 位字。
C.2 位邏輯函數C.2.1 atomicAnd()
int atomicAnd(int* address, int val);
unsigned int atomicAnd(unsigned int* address,
unsigned int val);
讀取位於全局或共享存儲器中地址address 處的32 位字old,計算 (old & val),並將結果存儲在存儲器的同一地址中。這三項操作在一次原子事務中執行。該函數將返回old。
C.2.2 atomicOr()
int atomicOr(int* address, int val);
unsigned int atomicOr(unsigned int* address,
unsigned int val);
讀取位於全局或共享存儲器中地址address 處的32 位字old,計算 (old | val),並將結果存儲在存儲器的同一地址中。這三項操作在一次原子事務中執行。該函數將返回old。
C.2.3 atomicXor()
int atomicXor(int* address, int val);
unsigned int atomicXor(unsigned int* address,
unsigned int val);
讀取位於全局或共享存儲器中地址address 處的32 位字old,計算 (old ^ val),並將結果存儲在存儲器的同一地址中。這三項操作在一次原子事務中執行。該函數將返回old。