You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:31:01