cuda的原子操作可以理解為對乙個變數進行「讀取-修改-寫入」這三個操作的乙個最小單位的執行過程,這個執行過程不能夠再分解為更小的部分,在它執行過程中,不允許其他並行執行緒對該變數進行讀取和寫入的操作。基於這個機制,原子操作實現了對在多個執行緒間共享的變數的互斥保護,確保任何一次對變數的操作的結果的正確性。
原子操作確保了在多個並行執行緒間共享的記憶體的讀寫保護,每次只能有乙個執行緒對該變數進行讀寫操作,乙個執行緒對該變數操作的時候,其他執行緒如果也要操作該變數,只能等待前一線程執行完成。原子操作確保了安全,代價是犧牲了效能。
cuda支援多種原子操作,常用的如下:
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 位字。
2、 atomicsub()
int atomicsub(int* address, int val);
unsigned int atomicsub(unsigned int* address, unsigned int val);
讀取位於全域性或共享儲存器中位址address 處的32 位字old,計算(old - val),並將結果儲存在儲存器的同一位址中。這三項操作在一次原子事務中執行。該函式將返回old。
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 位字。
4、 atomicmin()
int atomicmin(int* address, int val);
unsigned int atomicmin(unsigned int* address,unsigned int val);
讀取位於全域性或共享儲存器中位址address 處的32 位字old,計算old 和val 的最小值,並將結果儲存在儲存器的同一位址中。這三項操作在一次原子事務中執行。該函式將返回old。
5、 atomicmax()
int atomicmax(int* address, int val);
unsigned int atomicmax(unsigned int* address,unsigned int val);
讀取位於全域性或共享儲存器中位址address 處的32 位字old,計算old 和val 的最大值,並將結果儲存在儲存器的同一位址中。這三項操作在一次原子事務中執行。該函式將返回old。
6、 atomicinc()
unsigned int atomicinc(unsigned int* address,unsigned int val);
讀取位於全域性或共享儲存器中位址address 處的32 位字old,計算 ((old >= val) ? 0 : (old+1)),並將結果儲存在儲存器的同一位址中。這三項操作在一次原子事務中執行。該函式將返回old。
7、 atomicdec()
unsigned int atomicdec(unsigned int* address,unsigned int val);
讀取位於全域性或共享儲存器中位址address 處的32 位字old,計算 (((old == 0) | (old > val)) ? val : (old-1)),並將結果儲存在儲存器的同一位址中。這三項操作在一次原子事務中執行。該函式將返回old。
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 位字。
9、 atomicand()
int atomicand(int* address, int val);
unsigned int atomicand(unsigned int* address,unsigned int val);
讀取位於全域性或共享儲存器中位址address 處的32 位字old,計算 (old & val),並將結果儲存在儲存器的同一位址中。這三項操作在一次原子事務中執行。該函式將返回old。
10、 atomicor()
int atomicor(int* address, int val);
unsigned int atomicor(unsigned int* address,unsigned int val);
讀取位於全域性或共享儲存器中位址address 處的32 位字old,計算 (old | val),並將結果儲存在儲存器的同一位址中。這三項操作在一次原子事務中執行。該函式將返回old。
11、 atomicxor()
int atomicxor(int* address, int val);
unsigned int atomicxor(unsigned int* address,unsigned int val);
讀取位於全域性或共享儲存器中位址address 處的32 位字old,計算 (old ^ val),並將結果儲存在儲存器的同一位址中。這三項操作在一次原子事務中執行。該函式將返回old。
舉個例子,定義1024個執行緒,求這1024個執行緒的id之和,每個執行緒都會訪問總和變數sum,如果不加原子操作,執行結果是錯誤並且是不確定的。
[cpp]
view plain
copy
#include
#include
#include
#define size 1024
__global__ void
histo_kernel(
intsize, unsigned
int*histo)
} intmain(
void
)
使用原子操作正確的結果是523776,不使用原子操作的結果不確定,其中一次執行結果是711,顯然是不對的。
CUDA atomic原子操作
cuda的原子操作可以理解為對乙個變數進行 讀取 修改 寫入 這三個操作的乙個最小單位的執行過程,這個執行過程不能夠再分解為更小的部分,在它執行過程中,不允許其他並行執行緒對該變數進行讀取和寫入的操作。基於這個機制,原子操作實現了對在多個執行緒間共享的變數的互斥保護,確保任何一次對變數的操作的結果的...
5 1 CUDA atomic原子操作
和許多多執行緒並行問題一樣,cuda也存在互斥訪問的問題,即當乙個執行緒改變變數 而另外乙個執行緒在讀取變數 的值,執行原子操作類似於有乙個自旋鎖,只有等 的變數在改變完成之後,才能執行讀操作,這樣可以保證每一次讀取的都是最新的值.在kernel 程式中,做統計累加,都需要使用原子操作 atomic...
原子性,原子操作
舉個例子 a想要從自己的帳戶中轉1000塊錢到b的帳戶裡。那個從a開始轉帳,到轉帳結束的這乙個過程,稱之為乙個事務。在這個事務裡,要做如下操作 從a的帳戶中減去1000塊錢。如果a的帳戶原來有3000塊錢,現在就變成2000塊錢了。在b的帳戶裡加1000塊錢。如果b的帳戶如果原來有2000塊錢,現在...