核函数必须用__global__修饰且返回void,参数按值传递并指向设备内存,需cudamalloc分配、cudamemcpy拷贝、cudadevicesynchronize同步;启动语法为kernel,编译必须用nvcc。

核函数定义必须用 __global__ 修饰
不加这个关键字,编译器根本不会把它当 GPU 函数处理,链接时会报 undefined reference to 'kernel_name'。它不是可选语法糖,是 CUDA 编译器识别核函数的硬性标记。
-
__global__函数返回类型只能是void,哪怕你只想要一个状态码也不行 - 不能有非 void 返回值,也不能是类成员函数(除非显式绑定到对象指针并传入)
- 参数全部按值传递,指针参数指向的是设备内存——别直接传 host 数组地址
调用前必须先分配设备内存并拷贝数据
GPU 不能直接读 host 内存,cudaMemcpy 不是可选步骤,漏掉或方向写反(比如用 cudaMemcpyHostToDevice 却传了设备指针)会导致核函数读到全零或乱码。
- 用
cudaMalloc分配 device 内存,对应cudaFree释放,别混用malloc/free - 拷贝方向要严格匹配:host → device 用
cudaMemcpyHostToDevice,device → host 用cudaMemcpyDeviceToHost - 核函数执行完必须调用
cudaDeviceSynchronize()才能安全读回结果,否则可能拿到旧数据
启动语法里三个维度括号容易写错顺序
核函数调用后面那对双括号 >> 是 CUDA 特有语法,第一个括号是线程块配置,第二个是流(通常为 0),顺序和含义非常固定。
- 正确写法:
kernel_name>>(args...) -
grid_size和block_size都是整数,不是数组;想用二维布局得用dim3类型,比如dim3 grid(16, 16), block(8, 8) - 第三个参数是 shared memory 大小(字节),不写就是 0;第四个是 stream,不指定就用默认流(0)
- 常见错误:把
block_size写成总线程数(比如 1024),实际应是每块线程数,总块数由grid_size控制
编译必须用 nvcc,不能只靠 g++
CUDA 代码混着 host 和 device 逻辑,g++ 完全不认识 __global__、>> 这些符号,直接编译会报一堆语法错误。
立即学习“C++免费学习笔记(深入)”;
- 源文件后缀建议用
.cu,nvcc才会启用 CUDA 前端解析 - 主机代码(如
main())和核函数可以写在同一文件里,nvcc会自动分离编译 - 如果用 CMake,得调用
find_package(CUDA)并设置set_source_files_properties(file.cu PROPERTIES LANGUAGE CUDA),否则仍走 g++ 路径
printf 除外,且需用 __device__ 版本),也不能用 new/delete —— 这些细节在第一次跑出“结果没变”或“程序卡死”时才暴露,但原因往往藏在最基础的修饰符或内存路径里。










