2011-08-15 70 views
2

下面是我寫的一個小程序,用於查看CUDA中如何發生競爭情況,但我對輸出感到驚訝。CUDA程序的控制流程

#include<cutil.h> 
#include<iostream> 
__global__ void testLocal(int *something, int val[]){ 

*something = *something/2; 


val[threadIdx.x] = *something; 
} 

void main(){ 

    int *a, *c; 
    int r =16; 

    cudaMalloc((void**)&a, 4*sizeof(int)); 
    cudaMalloc((void**)&c, sizeof(int)); 
    cudaMemcpy(c, &r, sizeof(int) , cudaMemcpyHostToDevice); 
    testLocal<<<1,4>>>(c,a); 
    int *b = (int *)malloc(4 * sizeof(int)); 
    cudaMemcpy(b,a, 4 * sizeof(int), cudaMemcpyDeviceToHost); 

    for(int j =0 ; j< 4; j++){ 
     printf("%d\n",b[j]); 

    } 
    getchar(); 


} 

當我啓動4個線程時,我期望每個線程將*東西除以2。我知道他們分配某物的順序是不固定的。因此,當我試圖打印這些值時,我預計其中一個打印值爲8,其中一個爲4,一個爲2,一個爲1.但是,所有打印值均爲8.爲什麼是這樣?不應該所有的線程都會分開*一次。

回答

1

你在看什麼是未定義的行爲。由於您使用4個線程啓動單個塊,因此所有線程都在同一個warp中執行。這意味着

*something = *something/2; 

正在被您啓動的所有線程同時執行。 CUDA編程模型只保證當同一個warp中的多個線程嘗試寫入同一個內存位置時,其中一個寫入會成功。它沒有說明哪個線程會成功,並且在經線中的其他線程將不會「贏」的情況下會發生什麼。要獲得期望的行爲將需要序列化的內存訪問 - 這隻有通過在支持它們的體系結構上使用原子內存訪問原語纔是可能的。

1

應該是一個很強的詞。你在做什麼沒有說明,所以應該沒有做任何具體的事情。現在

,它可能確實是運行相同的計算單元上的4個線程,同樣內。 (「SIMT」模型使每個線程都作爲warp的一部分運行)。由於您在something上的操作不是原子操作,因此warp中的所有線程都會以鎖步方式讀寫內存。所以4個線程一起讀取*something,然後全部將結果除以2,並全部嘗試寫入8個內存。

你期待什麼,那*something被讀取和寫入原子是通過原子操作實現的,雖然沒有原子分裂或CUDA繁殖可用。所以如果你想真的想要這個,你需要編寫自己的(在atomicCAS的幫助下)。你會看到你的性能急劇下降,因爲你現在正在迫使那些努力並行運行的線程串行運行。

+0

鎖步是什麼意思?如果它們遵循鎖定機制,那麼執行是原子的。 – Programmer

+0

鎖定步驟意味着所有線程同時執行相同的指令。事實上,如果您使用CPU命名法,則與只有一個執行爲4寬SIMD的線程相當。一條指令從內存中讀取4個「線程」,一條指令執行除法,一條指令寫入4個值(到同一個內存位置)。 – Bahbar