我想实现一个设备端向量类,它封装了一个指向容器元素的指针。
在我实例化此类的对象后,我无法访问内部指针。它始终显示“访问违规写入位置某些设备内存地址”。
我的代码如下:
#include <iostream>
#include <cuda_runtime.h>
template <typename T>
class DeviceVector
{
private:
T* m_bValues;
std::size_t m_bSize;
public:
__host__
void* operator new(std::size_t size)
{
DeviceVector<T>* object = nullptr;
cudaMalloc((void**)&object, size);
return object;
}
__host__
void operator delete(void* object)
{
cudaFree(object);
}
__host__
DeviceVector(std::size_t size = 1)
{
cudaMemcpy(&m_bSize, &size, sizeof(std::size_t), cudaMemcpyHostToDevice);
// At this cudaMalloc I get Access violation writing location...
cudaMalloc((void**)&m_bValues, size * sizeof(T));
// It's an alternative solution here
T* ptr;
cudaMalloc((void**)&ptr, size * sizeof(T));
cudaMemcpy(&m_bValues, &ptr, sizeof(T*), cudaMemcpyHostToDevice);
// The memory is allocated
// But I can't access it through m_bValues pointer
// It is also Access violation writing location...
}
__host__
~DeviceVector()
{
// Access violation here if I use the second solution in the constructor
cudaFree(m_bValues);
}
};
int main()
{
DeviceVector<int>* vec = new DeviceVector<int>();
delete vec;
return 0;
}
注意: 我可以访问size属性。
所以我的问题是:
如何为这个类分配内存来访问里面的指针?
这甚至可以将指针封装到设备上的类中吗?
答案 0 :(得分:3)
这一行是非法的:
cudaMalloc((void**)&m_bValues, size * sizeof(T));
因为您的new
运算符在设备上分配了对象:
cudaMalloc((void**)&object, size);
return object;
并调用构造函数对分配进行操作。因此&m_bValues
将在主机代码中获取 device 变量的地址,这在CUDA中是非法的。如果你这样做,然后尝试在主机代码中使用它(即cudaMalloc
操作),你就会得到一个seg错误。 cudaMalloc
创建特定大小的设备分配,然后将该分配的设备指针存储在预期驻留在主机上的变量中。如果你传递一个设备地址来存储该指针,cudaMalloc
将会尝试写入指针值。
您的替代解决方案是一种更好的方法,并且当需要将指向设备分配的指针复制到驻留在设备上的变量时,这是一个通用的想法。
但您仍然基本上已经从主机进行m_bValues
指向无法访问的分配。 (ptr
,作为一个临时变量,不会有帮助,并且在类中创建另一个变量来保存像ptr
这样的值,因为整个类都没有帮助已分配并驻留在设备上。)出于同样的原因,您在之前的&m_bValues
操作中不允许使用cudaMalloc
,因此您无法使用直接在任何其他主机代码中使用它(复制指针值本身时,cudaMempcy
host-&gt;设备的目标除外)。
我认为没有任何简单的解决方法。我建议将对象重新设置为在主机上生存,并为相应的指针和参数(如size
)提供适当的主机和设备端分配。
你似乎也在重新发明轮子。您可能需要调查thrust device vectors(可以使用普通的CUDA代码轻松使用。)
无论如何,这是我能提出的最接近的:
#include <iostream>
#include <cuda_runtime.h>
#include <stdio.h>
#define cudaCheckErrors(msg) \
do { \
cudaError_t __err = cudaGetLastError(); \
if (__err != cudaSuccess) { \
fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
msg, cudaGetErrorString(__err), \
__FILE__, __LINE__); \
fprintf(stderr, "*** FAILED - ABORTING\n"); \
exit(1); \
} \
} while (0)
template <typename T>
class DeviceVector
{
private:
T* m_bValues;
std::size_t m_bSize;
std::size_t eleSize;
public:
__host__
void* operator new(std::size_t size)
{
DeviceVector<T>* object = NULL;
object = (DeviceVector<T> *)malloc(size*sizeof(DeviceVector<T>));
return object;
}
__host__
void operator delete(void* object)
{
free(object);
}
__host__
DeviceVector(std::size_t size = 1)
{
m_bSize = size;
eleSize = sizeof(T);
cudaMalloc(&m_bValues, m_bSize*sizeof(T));
cudaCheckErrors("constructor cudaMalloc fail");
cudaMemset(m_bValues, 0, m_bSize*sizeof(T));
}
__host__
~DeviceVector()
{
cudaFree(m_bValues);
cudaCheckErrors("destructor cudaFree fail");
}
__host__
T* getDevPtr(){
return m_bValues;}
__host__
std::size_t getSize(){
return m_bSize;}
__host__
std::size_t geteleSize(){
return eleSize;}
};
int main()
{
DeviceVector<int>* vec = new DeviceVector<int>();
cudaMemset(vec->getDevPtr(), 0xFF, vec->getSize()*vec->geteleSize());
cudaCheckErrors("vector fill fail");
delete vec;
return 0;
}
您对如何与此课程的对象进行互动几乎没有表现出来,所以我只是在这里猜测。