我正在尝试将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);
是否有可能使用托管内存并仍使用其构造函数初始化对象?
答案 0 :(得分:2)
正如Mark Harris here所讨论的,您可以为您的类重载new
和delete
运算符,以便通过托管内存API分配和释放实例,而不是通过主机标准库内存分配。这样做意味着您不能在设备代码中为您定义的任何类调用new
。
一个非常方便的设计模式(同样完全归功于Mark Harris博客的想法),是定义一个只包含合适的new
和delete
运算符的类,然后继承自当你定义自己的类将使用统一内存时。像这样:
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 ++惯用法正常工作。