VS2017 CUDA10.1 DLL封装及调用方法

为了调用方便和减少每次都没写.cu文件的麻烦和出错的几率,可以将编写好的CUDA并行程序生成dll动态库,每次使用是只需调用库的接口,省时省力,也便于集成到其他平台上。
环境:Win10,VS2017,CUDA10.1

封装动态库
  1. 启动VS2017,创建新项目
    步骤1
  2. 生成的工程如下,我们主要在CudaDll.h和CudaDll.cpp中进行修改
    步骤2
  3. 根据自己的目的修改CudaDll.h和CudaDll.cpp文件,在这里我们只需要一个函数的接口,因此把第一个框框出来的部分删掉,将函数名改为vectorAdd(int *a, int *b, int *c, int size);记得在函数前面加上前缀属性extern “C”

步骤3

// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 CUDADLL_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// CUDADLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef CUDADLL_EXPORTS
#define CUDADLL_API __declspec(dllexport)
#else
#define CUDADLL_API __declspec(dllimport)
#endif

// 此类是从 dll 导出的
//class CUDADLL_API CCudaDll {
//public:
//	CCudaDll(void);
//	// TODO: 在此处添加方法。
//};

//extern CUDADLL_API int nCudaDll;

extern "C" CUDADLL_API int vectorAdd(int *a, int *b, int *c, int size);
  1. 在CudaDll.cpp,删掉第一个框和第三个框的内容,将导出函数修改为我们需要的函数,然后先放一边,先去编写.cu文件,完成之后再来修改函数体的内容
    步骤4
// CudaDll.cpp : 定义 DLL 的导出函数。
//

#include "pch.h"
#include "framework.h"
#include "CudaDll.h"


 这是导出变量的一个示例
//CUDADLL_API int nCudaDll=0;

// 这是导出函数的一个示例。
extern "C" CUDADLL_API int vectorAdd(int *a, int *b, int *c, int size)
{
    return 0;
}

 这是已导出类的构造函数。
//CCudaDll::CCudaDll()
//{
//    return;
//}
  1. 右键点击源文件,选择“添加”,选择“新建项”
    步骤5
  2. 按照下面的方法往项目中添加kernel.cu文件,同样的方法添加kernel.h文件(添加.h文件要选择CUDA C/C++ Header)
    步骤6
    完成之后
    完成之后
  3. 将CUDA并行程序的主要内容编写到这两个文件之中,调用的接口写到kernel.cuh

kernel.cu的内容

#include "kernel.cuh"
//CUDA核函数  
__global__ void addKernel(int *c, const int *a, const int *b)
{
	int i = threadIdx.x;
	c[i] = a[i] + b[i];
}


//向量相加  
 int myVectorAdd(int *a, int *b, int *c, int size)
{
	int result = -1;
	int *dev_a = 0;
	int *dev_b = 0;
	int *dev_c = 0;
	cudaError_t cudaStatus;

	// 选择用于运行的GPU  
	cudaStatus = cudaSetDevice(0);
	if (cudaStatus != cudaSuccess) {
		result = 1;
		goto Error;
	}

	// 在GPU中为变量dev_a、dev_b、dev_c分配内存空间.  
	cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int));
	if (cudaStatus != cudaSuccess) {
		result = 2;
		goto Error;
	}
	cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int));
	if (cudaStatus != cudaSuccess) {
		result = 3;
		goto Error;
	}
	cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int));
	if (cudaStatus != cudaSuccess) {
		result = 4;
		goto Error;
	}

	// 从主机内存复制数据到GPU内存中.  
	cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);
	if (cudaStatus != cudaSuccess) {
		result = 5;
		goto Error;
	}
	cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);
	if (cudaStatus != cudaSuccess) {
		result = 6;
		goto Error;
	}

	// 启动GPU内核函数  
	addKernel << <1, size >> > (dev_c, dev_a, dev_b);

	// 采用cudaDeviceSynchronize等待GPU内核函数执行完成并且返回遇到的任何错误信息  
	cudaStatus = cudaDeviceSynchronize();
	if (cudaStatus != cudaSuccess) {
		result = 7;
		goto Error;
	}

	// 从GPU内存中复制数据到主机内存中  
	cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);
	if (cudaStatus != cudaSuccess) {
		result = 8;
		goto Error;
	}

	result = 0;

	// 重置CUDA设备,在退出之前必须调用cudaDeviceReset  
	cudaStatus = cudaDeviceReset();
	if (cudaStatus != cudaSuccess) {
		return 9;
	}
Error:
	//释放设备中变量所占内存  
	cudaFree(dev_c);
	cudaFree(dev_a);
	cudaFree(dev_b);

	return result;
}


kernel.cuh的内容

#pragma once
#include "cuda_runtime.h"  
#include "device_launch_parameters.h"    

__global__ void addKernel(int *c, const int *a, const int *b);
int myVectorAdd(int *a, int *b, int *c, int size);
  1. 修改项目的自定义方式为:CUDA10.1
    步骤8
    步骤9
  2. 修改cu文件的项类型
    步骤10
    步骤11
  3. 此时kernel.cu文件会有很多报错,没关系,把调试器改成x64,添加链接器的附加依赖项 cudart.lib
    步骤16
    步骤12
    步骤13
    步骤14
    完成之后,所有的报错都消失了
  4. 接下来回到CudaDll.cpp文件中添加kernel.cuh头文件并修改vectorAdd函数体
// CudaDll.cpp : 定义 DLL 的导出函数。
//
#include "pch.h"
#include "framework.h"
#include "CudaDll.h"
#include "kernel.cuh"

// 这是导出函数的一个示例。
CUDADLL_API int vectorAdd(int *a, int *b, int *c, int size)
{
	myVectorAdd(a, b, c, size);
    return 0;
}

  1. 进行到这里,就可以生成dll文件了
    步骤15
  2. 完成之后文件夹下生成了dll文件和lib文件(这一步失败的话,一定要去确定一下附加依赖项有没有正确添加cudart.lib
    步骤16
调用动态库

调用动态库就很简单啦
先新建好一个普通的工程(此处就不赘述了)
步骤18
将生成的CudaDll.h头文件、dll文件和lib文件拷贝到工程的当前目录下
在这里插入图片描述
记得把调试器改成x6,否则编译不通过!!!
记得修改!
修改工程属性,在附加依赖项处添加“CUDADLL.lib”(非常重要
步骤20
将头文件CudaDll.h添加到工程中
步骤21
编写调用程序进行测试

#include <iostream>
#include "CudaDll.h"

int main()
{
	const int size = 6;
	int a[size] = { 1, 2, 3,4,5,6 };
	int b[size] = { 12,14,16,18,20,22 };
	int c[size] = { 0 };
	int result = vectorAdd(a, b, c, size);
	printf("[%d, %d, %d, %d, %d, %d] \n + [%d, %d, %d, %d, %d, %d] \n= [%d, %d, %d, %d, %d, %d]",
		a[0], a[1], a[2], a[3], a[4], a[5],
		b[0], b[1], b[2], b[3], b[4], b[5],
		c[0], c[1], c[2], c[3], c[4], c[5]);
	return 0;
}

运行成功
完成

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值