CUDA內(nèi)存柵欄(Memory Fence)理解
CUDA中文教材的翻譯太晦澀了,英文文檔也全都是長(zhǎng)難句,導(dǎo)致內(nèi)存柵欄非常難理解。在本文中我會(huì)重新梳理一遍自己的理解,并用實(shí)驗(yàn)驗(yàn)證。
讓我們?cè)谌謨?nèi)存中初始化兩個(gè)變量:
然后在線程 i 中修改這兩個(gè)變量:
從線程 i 的視角來看,變量X的寫入在變量Y的寫入之前,這看似是對(duì)的,但編譯器會(huì)發(fā)現(xiàn)X和Y之間沒有依賴關(guān)系,然后把它們優(yōu)化成并行寫入,所以此時(shí)如果用另一個(gè)并行的線程讀取X和Y變量,X在Y之前寫入的這個(gè)順序就無法保證。讀取操作也是如此,順序無法得到保障。
讀取變量:
假設(shè)write和read函數(shù)分別由并行的線程 i 和線程 j 運(yùn)行,此時(shí)打印出來可能有四種結(jié)果:
????A=1, B=2?;? ?說明 j 在 i 之前讀取了變量,可以接受
????A=10, B=20;說明 i 在 j 之前寫入了變量,可以接受
????A=10, B=2;? 說明 i 已經(jīng)寫入A,但沒來得及寫入B,j 已經(jīng)讀取了變量,可以接受
????A=1, B=20;? ? ?說明 i 寫入順序被并行化,而B寫在了A前面,這是不能接受的情況,因?yàn)樗赡軙?huì)誤導(dǎo)其他線程
為了避免第四種情況的出現(xiàn),需要用內(nèi)存柵欄函數(shù),來保證線程 i 的讀寫順序從線程 j?的視角來看不會(huì)顛倒。完整代碼如下:
我們改變一下線程配置,就能出現(xiàn)不同的結(jié)果:
無論線程配置如何改動(dòng),都只會(huì)出現(xiàn)前三種可以接受的情況,而第四種情況是不可能出現(xiàn)的,因?yàn)閮?nèi)存柵欄__threadfence保證了讀寫順序。
新版的內(nèi)存柵欄函數(shù)似乎改名了(cuda::atomic_thread_fence),舊版的函數(shù)名可能會(huì)在未來被棄用。