CUDA 9.1(Ubuntu16.04 LTS)编译示例无报错但执行结果异常求助
解决CUDA程序编译正常但执行结果不符合预期的问题
嘿,我看你遇到了CUDA程序编译过了但跑出来结果不对的问题,大概率是主机(Host)和设备(Device)之间的内存拷贝步骤漏了或者写错了——毕竟你自己也怀疑内存传输没完成,这绝对是新手写CUDA程序时最容易踩的坑!
先看你给出的代码片段,main函数只写到int a, b, c; int *d_a, ...,明显是没写完完整的流程。一个能正确运行的CUDA加法程序,必须包含这几个核心步骤:主机端初始化变量、设备端分配内存、主机→设备传数据、启动核函数、设备→主机捞结果、释放设备内存。
我给你补全并修正后的完整代码如下:
#include <stdio.h> #include <iostream> using namespace std; __global__ void add(int *a, int *b, int *c){ *c = *a + *b; } // 加个CUDA错误检查宏,能帮你快速定位问题 #define CHECK_CUDA_ERROR(err) \ if (err != cudaSuccess) { \ cerr << "CUDA Error at " << __FILE__ << ":" << __LINE__ << ": " \ << cudaGetErrorString(err) << endl; \ exit(EXIT_FAILURE); \ } int main(void){ int a, b, c; int *d_a, *d_b, *d_c; // 1. 主机端初始化要计算的变量 a = 5; b = 3; c = 0; // 2. 给设备端的指针分配内存 CHECK_CUDA_ERROR(cudaMalloc((void**)&d_a, sizeof(int))); CHECK_CUDA_ERROR(cudaMalloc((void**)&d_b, sizeof(int))); CHECK_CUDA_ERROR(cudaMalloc((void**)&d_c, sizeof(int))); // 3. 把主机端的a、b拷贝到设备端的d_a、d_b里 CHECK_CUDA_ERROR(cudaMemcpy(d_a, &a, sizeof(int), cudaMemcpyHostToDevice)); CHECK_CUDA_ERROR(cudaMemcpy(d_b, &b, sizeof(int), cudaMemcpyHostToDevice)); // 4. 启动核函数:1个线程块,每个块1个线程(足够处理单个加法) add<<<1,1>>>(d_a, d_b, d_c); // 等待核函数执行完成,同时检查核函数是否有执行错误 CHECK_CUDA_ERROR(cudaDeviceSynchronize()); CHECK_CUDA_ERROR(cudaGetLastError()); // 5. 把设备端计算好的结果d_c拷贝回主机端的c CHECK_CUDA_ERROR(cudaMemcpy(&c, d_c, sizeof(int), cudaMemcpyDeviceToHost)); // 输出正确结果 cout << "a + b = " << c << endl; // 6. 别忘了释放设备端的内存,避免内存泄漏 cudaFree(d_a); cudaFree(d_b); cudaFree(d_c); return 0; }
关键注意点:
- 内存拷贝不能少:你原来的代码很大概率是没做
cudaMemcpy的双向拷贝——要么没把主机数据传到设备,核函数操作的是设备上的垃圾内存;要么没把设备计算结果拷回主机,输出的还是主机端初始化的默认值(比如你这里的c初始是0,可能最后输出就是0)。 - 一定要加错误检查:CUDA的API调用(比如
cudaMalloc、cudaMemcpy)和核函数执行都可能出错,但默认不会主动报错,加这个CHECK_CUDA_ERROR宏能帮你快速定位是哪一步出了问题,比如内存分配失败、拷贝方向写错(比如把cudaMemcpyHostToDevice写成cudaMemcpyDeviceToHost)。 - 核函数的异步特性:核函数是异步执行的,启动后主机端会继续往下跑,所以必须加
cudaDeviceSynchronize()等待核函数执行完再拷贝结果,不然可能拿到的是未完成计算的无效数据。
编译和执行命令:
用nvcc编译:
nvcc example3.cu -o example3
执行程序:
./example3
正常情况下会输出a + b = 8,就是正确结果了。
另外提醒一句:CUDA程序编译通过只代表语法没问题,不代表逻辑正确,内存拷贝、核函数配置这些逻辑问题,编译器是查不出来的,必须靠自己梳理清楚主机和设备的内存交互流程~
内容的提问来源于stack exchange,提问作者FranklinAQP
相关产品推荐
相关产品推荐

