在代码段here中,我遇到了共享内存定义和用法的结构。我将分配修改为静态,并在下面的测试程序中使用它:
#include <stdio.h>
template<class T, uint bDim>
struct SharedMemory
{
__device__ inline operator T *() {
__shared__ T __smem[ bDim ];
return (T*) (void *) __smem;
}
__device__ inline operator const T *() const {
__shared__ T __smem[ bDim ];
return (T*) (void *) __smem;
}
};
template <uint bDim>
__global__ void myKernel() {
SharedMemory<uint, bDim> myShared;
myShared[ threadIdx.x ] = threadIdx.x;
__syncthreads();
printf("%d\tsees\t%d\tat two on the circular right.\n", threadIdx.x, myShared[ ( threadIdx.x + 2 ) & 31 ]);
}
int main() {
myKernel<32><<<1, 32>>>();
cudaDeviceSynchronize();
return 0;
}
按预期工作正常。但是,我对此用法有几个问题:
sharedMemory
结构中运算符重载部分中使用的语法。是否重载了解引用运算符*
?如果是,那么通过方括号的访问如何转换为解引用指针?另外,为什么将__device__ inline operator T *() {
行更改为__device__ inline T operator *() {
会产生编译错误? 我希望通过重载赋值运算符或定义成员函数来简化包装器的使用,以便每个线程更新与其线程索引相对应的共享内存位置。因此,例如,写下myShared = 47;
或myShared.set( 47 );
会将myShared[threadIdx.x] = 47;
转换为幕后的0
。但我这样做并不成功。它编译得很好,但共享内存缓冲区全部读取template<class T, uint bDim>
struct SharedMemory
{
__device__ inline operator T*() {
__shared__ T __smem[ bDim ];
return (T*) (void *) __smem;
}
__device__ inline operator const T *() const {
__shared__ T __smem[ bDim ];
return (T*) (void *) __smem;
}
__device__ inline T& operator=( const T& __in ) {
__shared__ T __smem[ bDim ];
__smem[ threadIdx.x ] = __in;
return (T&) __smem[ threadIdx.x ];
}
__device__ inline void set( const T __in ) {
__shared__ T __smem[ bDim ];
__smem[ threadIdx.x ] = __in;
}
};
(我认为这是调试模式下的默认共享内存初始化)。能不能让我知道我做错了什么?这是我的尝试:
__shared__
对于成员函数,编译器发出警告:
变量&#34; __ smem&#34;已设置但从未使用过
虽然我知道member variables cannot be __shared__
,但我认为我错误的假设或我想做的事与java.io.File
限定符特征不匹配。我很感激帮助。
答案 0 :(得分:4)
看起来你对__shared__
访问说明符在CUDA中实际做了什么有一些误解,并且结合了一个相当棘手的模板,旨在欺骗编译器使用extern __shared__
内存的情况在模板化的内核实例中,引导你走盲道。
如果我理解你的需要,你真正想要的是这样的:
template<typename T>
struct wrapper
{
T * p;
unsigned int tid;
__device__ wrapper(T * _p, unsigned int _tid) : p(_p), tid(_tid) {}
__device__ const T* operator->() const { return p + tid; }
__device__ T& operator*() { return *(p + tid); }
__device__ const T& operator*() const { return *(p + tid); }
};
这是一个包装器,您可以使用它来“隐藏”指针和偏移量,以便“索引”自由访问指针,例如:
#include <cstdio>
// structure definition goes here
void __global__ kernel(float *in)
{
__shared__ float _buff[32];
wrapper<float> buff(&_buff[0], threadIdx.x);
*buff = in[threadIdx.x + blockIdx.x * blockDim.x];
__syncthreads();
for(int i=0; (i<32) && (threadIdx.x == 0); ++i) {
printf("%d %d %f\n", blockIdx.x, i, _buff[i]);
}
}
int main()
{
float * d = new float[128];
for(int i=0; i<128; i++) { d[i] = 1.5f + float(i); }
float * _d;
cudaMalloc((void **)&_d, sizeof(float) * size_t(128));
cudaMemcpy(_d, d, sizeof(float) * size_t(128), cudaMemcpyHostToDevice);
kernel<<<4, 32>>>(_d);
cudaDeviceSynchronize();
cudaDeviceReset();
return 0;
}
在示例内核中,共享内存数组_buff
用包装器实例中的线程索引包装,并且运算符重载允许您访问特定的数组元素,而无需通常的显式索引操作。也许您可以修改它以满足您的需求。