设备类中的设备指针(Cuda C ++)

时间:2015-03-08 11:10:16

标签: c++ pointers cuda

我想实现一个设备端向量类,它封装了一个指向容器元素的指针。

在我实例化此类的对象后,我无法访问内部指针。它始终显示“访问违规写入位置某些设备内存地址”。

我的代码如下:

#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属性。

所以我的问题是:
如何为这个类分配内存来访问里面的指针?
这甚至可以将指针封装到设备上的类中吗?

1 个答案:

答案 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;
}

您对如何与此课程的对象进行互动几乎没有表现出来,所以我只是在这里猜测。