CUDA學習筆記
線程的索引和它的線程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);
...
}
對於其它維度的線程塊和線程索引,可以依照這樣的思想類比得到。這裏不再贅述,有疑問的可以在評論區交流。