【CUDA學習筆記(二)】線程threadIdx、線程塊blockIdx索引詳解

線程的索引和它的線程ID以一種簡單的方式相互關聯,threadIdx、blockIdx、blockDim是內置變量,用於索引線程位置。線程索引方式對於並行編程至關重要,它制約着內核函數中對循環的改寫方式。

線程塊需要獨立執行:必須能夠以任何順序執行它們,並行執行或串行執行。這種獨立性要求允許以任意順序跨任意數量的內核調度線程塊。塊中的線程可以通過一些共享內存共享數據,並通過同步它們的執行來協調內存訪問進行協作。更準確地說,可以通過調用內部函數來指定內核中的同步點;作爲一個屏障,在這個屏障上,塊中的所有線程都必須等待,然後才允許任何線程繼續。

1.一維線程、一維線程塊索引

threadIdx是一個三維矢量,包括threadIdx.x、threadIdx.y、threadIdx.z,對於函數主題設置爲一維的線程的索引,僅用到threadIdx.x,下面展示一維線程索引。

// Kernel definition
__global__ void VecAdd(float* A, float* B, float* C)
{
    int i = threadIdx.x;
    C[i] = A[i] + B[i];
}

int main()
{
    ...
    // 1個線程網格上的線程塊個數,N:一個線程塊上的線程個數
    VecAdd<<<1, N>>>(A, B, C);
    ...
}

2.二維線程、二維線程塊索引

線程和線程塊均按二維排列的情況如下圖,blockIdx爲block索引的內置變量,是一個三維矢量;blockDim爲一個block塊包含的線程規模,也是一個三維矢量(例如下圖中一個block中包含4列3行線程,因此blockDim.x大小爲4,blockDim.y大小爲3)。因此圖中Thread(0,0)的線程索引爲
i=blockIdx.x * blockDim.x+threadIdx.x;
j=blockIdx.y * blockDim.y + threadIdx.y;

在這裏插入圖片描述
下面是一個二維線程、二維線程塊索引的示例。

// Kernel definition
__global__ void MatAdd(float A[N][N], float B[N][N],
float C[N][N])
{
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    int j = blockIdx.y * blockDim.y + threadIdx.y;
    if (i < N && j < N)
        C[i][j] = A[i][j] + B[i][j];
}

int main()
{
    ...
    // Kernel invocation
    dim3 threadsPerBlock(16, 16);
    dim3 numBlocks(N / threadsPerBlock.x, N / threadsPerBlock.y);
    MatAdd<<<numBlocks, threadsPerBlock>>>(A, B, C);
    ...
}

對於其它維度的線程塊和線程索引,可以依照這樣的思想類比得到。這裏不再贅述,有疑問的可以在評論區交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章