質問: A[i][j] + B[i][j]; } int main() { ... // Kernel invocation dim3 threadsPerBlock(16, 16); dim3 numBlocks(N / threadsPerBlock.x, N / threadsPerBlock.y); MatAdd<<>>(A, B, C); ... } ```
回答: 厳密なことを省いて概要だけを説明しますと、`MatAdd<<>>(A, B, C);`で渡されている、 `numBlocks, threadsPerBlock`分、スレッドが生成されます。この場合、N個のスレッドが生成されます。 N個のスレッドがそれぞれ、カーネルコードである`MatAdd()`を実行します。つまり、 `MatAdd()`がN個のスレッドで個別に処理されています。 このカーネルには、スレッド固有の情報がCUDAによって付与されています。 `blockDim.x`はX軸のスレッドブロック数、 `blockIdx.x`は今実行されているスレッドのX軸のスレッドブロックのインデックス値、`thread.x`は今実行されているスレッドのインデックス値が入ります。Y軸も同様です。 各スレッドは上記の値を使ってどの配列にアクセスすべきかを決めています。 それが ``` int i = blockIdx.x * blockDim.x + threadIdx.x; int j = blockIdx.y * blockDim.y + threadIdx.y; ``` の部分です。 ですので、配列サイズよりも大きいスレッドを生成した場合、簡単にメモリ領域外アクセスを起こします。このため配列サイズでのアクセスチェックは必ず行ってください。 スレッドはいくらでも呼び出すことができます(上限はありますが)し、実際にはWarpと呼ばれるスレッドグループで32スレッドずつスレッドが実行されますので注意が必要です。