CUDA中如何将结构体类型vector从CPU传递至GPU?
问题分析与解决方案
错误根源
出现"Access violation error"的核心原因基本是主机端IntensityMat[i].pImgBuf指向的内存无效——要么是空指针、要么没提前分配内存存储图像数据、甚至可能已经被释放。另外也得检查bpp的值是否合法(比如是不是8的整数倍,避免计算图像缓冲区大小时出现0或负数)。
修正后的内存拷贝代码
先确认主机端每个IntensityVal的pImgBuf都已正确分配并加载了图像数据,再按以下步骤完成设备端内存拷贝:
// 1. 给设备端的结构体数组分配内存 IntensityVal* deviceIntensityMat = nullptr; cudaMalloc((void**)&deviceIntensityMat, IntensityMat.size() * sizeof(IntensityVal)); // 每次CUDA操作后建议检查错误,快速定位问题 if (cudaGetLastError() != cudaSuccess) { // 这里可以加错误提示或直接退出 return; } // 保存所有设备端图像缓冲区的指针,方便后续统一释放 std::vector<BYTE*> deviceImgBufs; for (size_t i = 0; i < IntensityMat.size(); ++i) { // 先校验主机端数据的有效性 if (IntensityMat[i].pImgBuf == nullptr || IntensityMat[i].bpp % 8 != 0) { // 跳过无效数据或者直接报错退出,根据需求调整 continue; } int imgBufSize = IntensityMat[i].width * IntensityMat[i].height * (IntensityMat[i].bpp / 8); if (imgBufSize <= 0) { continue; } BYTE* deviceImgBuf = nullptr; cudaMalloc((void**)&deviceImgBuf, imgBufSize); if (cudaGetLastError() != cudaSuccess) { continue; } deviceImgBufs.push_back(deviceImgBuf); // 把主机端图像数据拷贝到设备端缓冲区 cudaMemcpy(deviceImgBuf, IntensityMat[i].pImgBuf, imgBufSize, cudaMemcpyHostToDevice); if (cudaGetLastError() != cudaSuccess) { // 拷贝失败的话,要把刚分配的设备端缓冲区释放掉 cudaFree(deviceImgBuf); deviceImgBufs.pop_back(); continue; } // 构造设备端结构体并拷贝到设备端数组 IntensityVal temp = { IntensityMat[i].width, IntensityMat[i].height, IntensityMat[i].bpp, deviceImgBuf }; cudaMemcpy(&deviceIntensityMat[i], &temp, sizeof(IntensityVal), cudaMemcpyHostToDevice); }
设备端内存释放方法
释放要分两步:先逐个释放图像缓冲区,再释放结构体数组的内存:
// 1. 释放所有设备端的图像缓冲区 for (auto buf : deviceImgBufs) { if (buf != nullptr) { cudaFree(buf); } } // 2. 释放设备端的结构体数组 if (deviceIntensityMat != nullptr) { cudaFree(deviceIntensityMat); }
额外注意点
- 调用CUDA核函数时,要传
deviceIntensityMat这个设备端指针,不能直接传主机端的IntensityMat。 - 所有CUDA操作后都用
cudaGetLastError()检查错误,能快速定位内存分配、拷贝的问题。 - 如果
bpp存在非8倍数的可能,要加容错逻辑,避免计算出无效的缓冲区大小。
内容的提问来源于stack exchange,提问作者Md. Rokonuzzaman Reza
相关产品推荐
相关产品推荐

