如何将cudaMallocManaged与带有构造函数的对象一起使用

时间:2018-01-22 02:13:44

标签: c++ cuda

我正在尝试将CUDA管理的内存与我通过构造函数创建的对象结合使用。

struct A {
    A(float x) : x(x) {}
    float x;
}

__global__ void myKernel(A *a) {
    printf("%f", a->x);
}

int main() {
    A *a;
    cudaMallocManaged(&a, sizeof(A));
    a->x = 42.f;        // This works
    // a = new a(42.f); // This obviously doesn't because a doesn't point
                        // to managed memory now.
    myKernel<<<1,1>>>(a);
}

使用构造函数而不是直接初始化a->x = ...A更复杂的类更方便。

我当然可以使用构造函数创建对象a,并使用“普通”cudaMalloc和cudaMemcpy,如下所示。

A a(42.f);
A *d_a;
cudaMalloc(&d_a, sizeof(A));
cudaMemcpy(d_a, &a, sizeof(A), cudaMemcpyHostToDevice);

是否有可能使用托管内存并仍使用其构造函数初始化对象?

1 个答案:

答案 0 :(得分:2)

正如Mark Harris here所讨论的,您可以为您的类重载newdelete运算符,以便通过托管内存API分配和释放实例,而不是通过主机标准库内存分配。这样做意味着您不能在设备代码中为您定义的任何类调用new

一个非常方便的设计模式(同样完全归功于Mark Harris博客的想法),是定义一个只包含合适的newdelete运算符的类,然后继承自当你定义自己的类将使用统一内存时。像这样:

class Managed {
public:
  void *operator new(size_t len) {
    void *ptr;
    cudaMallocManaged(&ptr, len);
    cudaDeviceSynchronize();
    return ptr;
  }

  void operator delete(void *ptr) {
    cudaDeviceSynchronize();
    cudaFree(ptr);
  }
};

class A : public Managed
{
public:
    A(float x) : x(x) {}
    float x;
}

// ....

A *a = new A(42.f);

请注意,理想情况下,您还应该为数据类定义赋值运算符,以便复制构造和其他有用的C ++惯用法正常工作。