CUDA中对于语言C++的编程扩展有很详细的说明,我采用的就是C++编程,根据之前提到过的异构编程思想,首先C++语言提供必要的串行代码,但是并行代码部分如何编写?并行代码部分主要靠CUDA中C++扩展的函数来实现。这里首先介绍如何定义GPU设备上执行的函数,然后详细介绍主机和设备之间内存开辟和数据传输问题。
C++扩展函数定义、变量定义
1.函数执行空间说明符
函数执行空间说明符表示一个函数是在主机上执行还是在设备上执行,以及它是可以从主机上调用还是从设备上调用。这里涉及两个问题,一个是执行、一个是调用。
1.1__global__
代码的执行空间说明符__global__将一个函数声明为内核。这样的函数可以:
1)在设备上执行;
2)在主机上调用;
3)在设备上调用;
一个__global__函数必须具有void返回类型,并且不能是一个类的成员。
对一个__global__函数的调用是异步的,这意味着它在设备完成执行之前返回。因此这样的函数在主函数中需要同步语句。
1.2__device__
__device__执行空间说明符声明了一个函数:
1)在设备上执行;
2)只能从设备上调用;
不能同时使用__global__和__device__执行空间说明符。
1.3__host__
__host__执行空间指定符声明了一个函数:
1)在主机上执行
2)只能从主机调用
它等价于只使用__host__执行空间说明符来声明一个函数,或者不使用任何__host__、__global__和__device__执行空间说明符来声明它;在这两种情况下,函数都只为主机编译
host、__global__执行空间指定符不能同时使用。
但是,可以同时使用__device__和__host__执行空间说明符
1.4__noinline__ 和__forceinline__
当认为合适时,编译器会内联任意的__device__函数。
可以使用__noinline__ 函数限定符作为提示,让编译器尽可能不内联函数。
可以使用__forceinline__函数限定符强制编译器内联函数。
函数限定符不能同时使用,而且两个函数限定符都不能应用于内联函数。
2.变量内存空间说明符
变量内存空间说明符表示变量在设备上的内存位置。
在设备代码中声明的一个自动变量,在本节中描述的内存空间说明符中没有使用任何__device__或者__shared__ 或者__constant__说明符 ,通常存在于寄存器中。但是,在某些情况下,编译器可能会选择将它放在本地内存中,这可能会产生不良的性能后果。
2.1__device__
__device__内存空间说明符声明了一个存在于设备上的变量。
在接下面介绍的__constant__或者__shared__或者__managed__内存空间说明符中,最多有一个可以与__device__一起使用,以进一步指示变量属于哪个内存空间。如果它们都不存在,变量:
1)存在于全局内存空间中;
2)在它创建后具有CUDA环境的生存周期;
3)每个设备有一个不同的对象;
4)可以从Grid内的所有线程访问,或者通过runtime库(cudaGetSymbolAddress() / cudaGetSymbolSize() / cudaMemcpyToSymbol() / cudaMemcpyFromSymbol())从主机访问。
2.2__constant__
__constant__内存空间说明符,可选地与__device__说明符一起使用,声明了一个变量:
1)存在于常量内存空间中;
2)在它创建后具有CUDA环境的生存周期;
3)每个设备有一个不同的对象;
4)可以从Grid内的所有线程访问,或者通过runtime库(cudaGetSymbolAddress() / cudaGetSymbolSize() / cudaMemcpyToSymbol() / cudaMemcpyFromSymbol())从主机访问。
2.3__shared__
__shared__内存空间说明符,可选地与__device__说明符一起使用,声明了一个变量:
1)存在于线程块(block)的共享内存空间中,
2)具有和块(block)一样的生命周期,
3)每个block有一个不同的对象,
4)只能从块内的所有线程访问,
5)没有固定地址。
2.4__managed__
__shared__内存空间说明符,可选地与__device__说明符一起使用,声明了一个变量:
1)可以从设备和主机代码中引用,例如,它的地址可以被获取,也可以直接从设备或主机函数中读取或写入。
2)具有应用程序的生存期。