CUDA C 學(xué)習(xí)筆記_1.0.8
原子操作
? ? ? ?CUDA的原子操作可以理解為:對(duì)變量的 “讀取-修改-寫(xiě)入” 這三個(gè)操作進(jìn)行捆綁或鎖定,成為最小執(zhí)行單位,不允許分解和打斷。例如:當(dāng)一個(gè)線程對(duì)某一個(gè)變量執(zhí)行?“讀取-修改-寫(xiě)入” 的操作時(shí),此時(shí)第二個(gè)線程也需要對(duì)同一個(gè)變量執(zhí)行?“讀取-修改-寫(xiě)入” 的操作:
? ? ? ?(1) 在不進(jìn)行原子操作時(shí),如果第二個(gè)線程讀取時(shí)第一個(gè)線程還未寫(xiě)入,則讀取和第一個(gè)線程相同的值,如果第一個(gè)線程已經(jīng)寫(xiě)入完成,就會(huì)讀取第一個(gè)線程寫(xiě)入的值,導(dǎo)致計(jì)算出現(xiàn)錯(cuò)誤。
? ? ? ?(2) 添加原子操作之后,如果在第一個(gè)線程操作完成之前,第二個(gè)線程的操作會(huì)被阻止,不允許其?“讀取-修改-寫(xiě)入” ,只有等帶沒(méi)有線程操作該變量時(shí)才被允許。所以第二個(gè)線程只會(huì)讀取到第一個(gè)線程寫(xiě)入的值。
? ? ? ?基于這個(gè)機(jī)制,原子操作實(shí)現(xiàn)了對(duì)在多個(gè)線程間共享的變量的互斥保護(hù),確保任何一次對(duì)變量的操作的結(jié)果的正確性。CUDA 中的原子操作與共享內(nèi)存具有一些相似之處,都會(huì)使原本互不影響的各個(gè)線程之間產(chǎn)生依賴和相互作用。所不同的是,共享內(nèi)存是 “ 線程塊 ” 級(jí)別的,對(duì)于處于不同線程塊之中的兩個(gè)線程,依然不會(huì)因?yàn)楣蚕韮?nèi)存的存在而產(chǎn)生相互作用;而原子操作是全局的,針對(duì)的是核函數(shù)啟動(dòng)時(shí)所喚醒的全部線程。
? ? ? ?另外,從某種意義上講,共享內(nèi)存的使用初衷是為了提高計(jì)算效率,實(shí)現(xiàn)多個(gè)線程對(duì)重復(fù)數(shù)據(jù)的快速訪問(wèn);原子操作更多的是為了保證計(jì)算結(jié)果正確的同時(shí),避免?host (主機(jī)端) 的介入,在一定程度上會(huì)降低計(jì)算效率。
原子函數(shù)的使用
原子操作通過(guò)原子函數(shù)實(shí)現(xiàn),常用的原子函數(shù)主要有以下幾種:
(1) 加法
atomicAdd(&value, num); -----------value = value + num
(2) 減法
atomicSub(&value, num); -----------value = value - num
(3) 賦值
atomicExch(&value, num); ----------value = num
(4) 最大值
atomicMax(&value, num); -----------value = max(value, num)
(5) 最小值
atomicMin(&value, num); ------------value = max(value, num)
? ? ? ?原子函數(shù)雖然目前功能比較有限,但其不僅可以使用在 ”線程塊“ 級(jí)別,還可以使用在整個(gè)設(shè)備端的全局內(nèi)存范圍,并且最新的 CUDA 計(jì)算還可以實(shí)現(xiàn)整個(gè)計(jì)算域 (CPU+GPU) 級(jí)別的原子操作。