在CUDA中防止内核调用后的析构函数调用

在CUDA中防止内核调用后的析构函数调用,cuda,raii,Cuda,Raii,考虑到我的问题的简化版本:为了将数据传递给CUDA内核,我使用了一个类来保存数据和一个指向图形硬件上数据的指针 class A { int data; float* dataOnGPU; A() { cudaMalloc( dataOnGPU ... ); } ~A() { cudaFree( dataOnGPU ... ); } }; void myFunction() { A obj; kernelCall1<<<1,1>>>(

考虑到我的问题的简化版本:为了将数据传递给CUDA内核,我使用了一个类来保存数据和一个指向图形硬件上数据的指针

class A {
  int data;
  float* dataOnGPU;
  A() { cudaMalloc( dataOnGPU ... ); }
  ~A() { cudaFree( dataOnGPU ... ); }
};

void myFunction()
{
  A obj;
  kernelCall1<<<1,1>>>( obj );
  kernelCall2<<<1,1>>>( obj ); // obj.dataOnGPU no longer points to valid memory

}
A类{
int数据;
浮动*大东圃;
A()
~A()
};
void myFunction()
{
obj;
内核调用1(obj);
kernelCall2(obj);//obj.dataOnGPU不再指向有效内存
}
从第一个内核调用返回将导致调用obj副本的析构函数(因为内核是按值调用的,这将创建一个副本)。这使大东浦可以获得obj及其副本。obj.dataOnGPU的内存在obj超出范围之前不应空闲


当然,有可能避免这种情况,但我希望有好的、干净的RAII行为。有什么建议吗?

您可以将析构函数更改为:

~A() { cudaDeviceSynchronize(); cudaFree( dataOnGPU ... ); }

因此,在释放内存之前,内核运行到完成状态。

使用自定义复制构造函数是解决方案:

class A {
  int data;
  float* dataOnGPU;
  bool isCopy;
  A() { cudaMalloc( dataOnGPU ... ); isCopy = false; }
  A( const A& _orig ) { *this = _orig; isCopy = true; }
  ~A() { if (!isCopy) cudaFree( dataOnGPU ... ); }
};

void myFunction()
{
  A obj;
  kernelCall1<<<1,1>>>( obj );
  kernelCall2<<<1,1>>>( obj ); // obj.dataOnGPU still points to valid memory
}
A类{
int数据;
浮动*大东圃;
bool-isCopy;
A(){cudamaloc(大东普…;isCopy=false;}
(常数A&_orig){*this=_orig;isCopy=true;}
~A()
};
void myFunction()
{
obj;
内核调用1(obj);
kernelCall2(obj);//obj.dataOnGPU仍然指向有效内存
}

感谢Paul R间接地向我指出这一点:)

这仍然会释放obj.dataOnGPU,它应该在第二次内核调用中可用。好的-那么您的a类只有一个浅拷贝?是的,没错。我假设指定no copy构造函数表示执行了浅层复制。好吧-我认为您的基本设计被破坏了-为什么不通过引用将a传递给内核调用呢?这(技术上)是不可能的,但是您可以使用copy构造函数。