1. CUDA函数执行空间限定符深度解析
在CUDA并行编程中,函数执行空间限定符是构建异构计算系统的关键语法元素。它们定义了函数在主机(CPU)还是设备(GPU)上执行,以及可以被哪些执行环境调用。理解这些限定符的细微差别,是编写高效、正确CUDA代码的基础。
1.1 __global__函数:设备执行的入口点
__global__修饰的函数就是我们常说的"内核函数",它是主机代码调用设备计算的桥梁。在实际项目中,我经常用它来实现矩阵运算、图像处理等并行计算密集型任务。
这个限定符有几个重要特性需要特别注意:
- 异步执行:主机调用内核后会立即继续执行后续代码,不会等待内核完成。这既是优势也是陷阱。我曾在一个图像处理项目中因为忽略这点导致结果错误,后来通过添加
cudaDeviceSynchronize()才解决问题。 - 调用限制:内核函数必须返回void,且不能是类的成员函数。如果尝试让内核返回数值,编译器会直接报错。
- 动态并行:计算能力5.0+的设备支持从设备代码调用内核,这为更复杂的算法设计提供了可能。但在实际使用中要注意控制调用深度,避免栈溢出。
典型的内核调用语法示例:
cpp复制// 内核定义
__global__ void vectorAdd(float* A, float* B, float* C, int N) {
int i = blockIdx.x * blockDim.x + threadIdx.x;
if (i < N) C[i] = A[i] + B[i];
}
// 主机调用
int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock;
vectorAdd<<<blocksPerGrid, threadsPerBlock>>>(d_A, d_B, d_C, N);
1.2 __device__函数:设备端的工具函数
__device__函数是GPU上的"本地函数",只能被其他设备函数或内核调用。在我的CUDA编程实践中,常把一些会被多个内核复用的计算逻辑封装成__device__函数。
关键特点包括:
- 设备专用:无法从主机直接调用,这点与
