除了直接在專案中使用cu或cuh來編寫cuda**之外,還可以將cuda相關操作**放在乙個dll專案中,將專案編譯成動態鏈結庫dll,然後在需要使用的專案中引用這個dll並呼叫其內部函式即可。
現在新建乙個dll專案,專案名稱為test00302,如下圖所示:
現在在專案中新建乙個名為test.cu的檔案,如下圖所示:
然後設定專案的生成自定義方式為,如下圖所示:
然後設定test.cu的屬性中「項型別」為「cuda c/c++」,如下圖所示:
在test.cu中新增如下**:
#include #include #include //cuda執行時庫標頭檔案
using namespace std;
extern "c"
//顯示裝置資訊
void showdeviceprop(void)
else
freelibrary(mycudadll);//動態地解除安裝dll檔案
執行專案test00303,其結果如下圖所示:
專案test00303為普通的控制台應用程式,test00302.dll為編譯的包含cuda函式的動態鏈結庫,通過動態引用,即可在普通的應用程式裡面載入cuda程式。
下面再用呼叫cuda核心函式的進行測試,先在專案test00302中新建乙個名為test2.cu的檔案,在test2.cu中新增gpu中執行的核函式addkernel(),然後新增用於向量相加的函式vectoradd(),在函式vectoradd()中選擇用於執行的gpu裝置、在裝置上分配記憶體、複製主機記憶體資料到裝置記憶體、啟動核函式、呼叫cudadevicesynchronize()監聽核函式執行、複製裝置記憶體資料到主機記憶體、重置cuda裝置、釋放裝置記憶體。test2.cu中的**如下:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include extern "c"
//cuda核函式
__global__ void addkernel(int *c, const int *a, const int *b)
//向量相加
int vectoradd(int c, int a, int b,int size)
// 在gpu中為變數dev_a、dev_b、dev_c分配記憶體空間.
cudastatus = cudamalloc((void**)&dev_c, size * sizeof(int));
if (cudastatus != cudasuccess)
cudastatus = cudamalloc((void**)&dev_a, size * sizeof(int));
if (cudastatus != cudasuccess)
cudastatus = cudamalloc((void**)&dev_b, size * sizeof(int));
if (cudastatus != cudasuccess)
// 從主機記憶體複製資料到gpu記憶體中.
cudastatus = cudamemcpy(dev_a, a, size * sizeof(int), cudamemcpyhosttodevice);
if (cudastatus != cudasuccess)
cudastatus = cudamemcpy(dev_b, b, size * sizeof(int), cudamemcpyhosttodevice);
if (cudastatus != cudasuccess)
// 啟動gpu核心函式
addkernel<<<1, size>>>(dev_c, dev_a, dev_b);
// 採用cudadevicesynchronize等待gpu核心函式執行完成並且返回遇到的任何錯誤資訊
cudastatus = cudadevicesynchronize();
if (cudastatus != cudasuccess)
// 從gpu記憶體中複製資料到主機記憶體中
cudastatus = cudamemcpy(c, dev_c, size * sizeof(int), cudamemcpydevicetohost);
if (cudastatus != cudasuccess)
result=0;
// 重置cuda裝置,在退出之前必須呼叫cudadevicereset
cudastatus = cudadevicereset();
if (cudastatus != cudasuccess)
error:
//釋放裝置中變數所佔記憶體
cudafree(dev_c);
cudafree(dev_a);
cudafree(dev_b);
return result;
}
編譯專案test00302,在生成的動態鏈結庫檔案test00302.dll複製到專案test00303的debug資料夾下,然後修改專案
test00303中的檔案test00303.cpp內容如下:
// test00303.cpp : 定義控制台應用程式的入口點。
#include "stdafx.h"
#include #include #include typedef int(*dllfunc)(void);//宣告需要從dll中呼叫的函式原型的函式指標
typedef int(*dllfunc2)(int *c, int *a, int *b,int size);//宣告需要從dll中呼叫的函式原型的函式指標
int _tmain(int argc, _tchar* argv)
//else
////呼叫dll中的vectoradd函式
dllfunc2 dllfun2=(dllfunc2)getprocaddress(mycudadll,"vectoradd");//獲得函式指標
if (dllfun2)
; int b[arraysize] = ;
int c[arraysize] = ;
int r=dllfun2(c,a,b,arraysize);//執行函式
if(r==0)
+ = \n",
c[0], c[1], c[2], c[3], c[4]);
}else
printf("計算失敗\n");
} else
freelibrary(mycudadll);//動態地解除安裝dll檔案
} else
system("pause");
return 0;
}
由於dll中的函式vectoradd 定義如下:
int vectoradd(int c, int a, int b,int size);
所以在宣告函式的原型指標時也需要定義為:
typedef
int(*dllfunc2)(int *c, int *a, int *b,int size);
或:typedef
int(*dllfunc2)(int c, int a, int b,int size);
執行專案test00303,其結果如下圖所示:
雖然這個例子比較簡單,但是向量相加的計算過程是由gpu完成的。
GCC 編譯使用動態鏈結庫
動態鏈結庫 1.建立動態鏈結庫 複製 如下 include void hello 用命令gcc shared hello.c o libhello.so編譯為動態庫。可以看到,當前目錄下多了乙個檔案libhello.so。2.再編輯乙個測試檔案test.c,內容如下 複製 如下 include in...
GCC 編譯使用動態鏈結庫和靜態鏈結庫
1 庫的分類 根據鏈結時期的不同,庫又有靜態庫和動態庫之分。靜態庫是在鏈結階段被鏈結的 好像是廢話,但事實就是這樣 所以生成的可執行檔案就不受庫的影響了,即使庫被刪除了,程式依然可以成功執行。有別於靜態庫,動態庫的鏈結是在程式執行的時候被鏈結的。所以,即使程式編譯完,庫仍須保留在系統上,以供程式執行...
GCC 編譯使用動態鏈結庫和靜態鏈結庫
1 庫的分類 根據鏈結時期的不同,庫又有靜態庫和動態庫之分。靜態庫是在鏈結階段被鏈結的 好像是廢話,但事實就是這樣 所以生成的可執行檔案就不受庫的影響了,即使庫被刪除了,程式依然可以成功執行。有別於靜態庫,動態庫的鏈結是在程式執行的時候被鏈結的。所以,即使程式編譯完,庫仍須保留在系統上,以供程式執行...