也许您应该包含一个完整的简单示例。(如果我在上面编译您的代码并自行运行它,在 linux 上,我会在第二个 cudaMalloc 操作时遇到 seg 错误)。我看到的一个问题是,由于您在第一步中已在设备内存中分配了粒子对象,因此当您分配_w
指针时,您将指针传递给已经在设备内存中的 cudaMalloc。您应该将基于主机的指针传递给 cudaMalloc,然后它将分配给设备(全局)内存中的分配区域。
我认为符合我在 yoru 示例中看到的一种可能的解决方案是这样的:
#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)
class Particle
{
public:
double *_w;
};
__global__ void test(Particle *p){
int idx=threadIdx.x + blockDim.x*blockIdx.x;
if (idx == 2){
printf("dev_p[2]._w[2] = %f\n", p[idx]._w[2]);
}
}
int main() {
int nParticles=100;
Particle *dev_p;
double *w[nParticles];
cudaMalloc((void**)&dev_p, nParticles * sizeof(Particle));
cudaCheckErrors("cudaMalloc1 fail");
for( int i = 0; i < nParticles; i++){
cudaMalloc((void**)&(w[i]), 300 * sizeof(double));
cudaCheckErrors("cudaMalloc2 fail");
cudaMemcpy(&(dev_p[i]._w), &(w[i]), sizeof(double *), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy1 fail");
}
double testval = 32.7;
cudaMemcpy(w[2]+2, &testval, sizeof(double), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy2 fail");
test<<<1, 32>>>(dev_p);
cudaDeviceSynchronize();
cudaCheckErrors("kernel fail");
printf("Done!\n");
}
在这里,我们在主机上创建一组单独的指针以用于 cudaMalloc 目的,然后将这些分配的指针复制到设备以用作设备指针(这对于 UVA 是合法的)。
另一种方法是在设备端分配 _w 指针。这也可能符合您的目的。
以上所有我都假设 cc 2.0 或更高版本。
使用类似于此处描述的方法,可以将循环中完成的设备端分配折叠为单个分配:
cudaMalloc(&(w[0]), nParticles*300*sizeof(double));
cudaCheckErrors("cudaMalloc2 fail");
cudaMemcpy(&(dev_p[0]._w), &(w[0]), sizeof(double *), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy1 fail");
for( int i = 1; i < nParticles; i++){
w[i] = w[i-1] + 300;
cudaMemcpy(&(dev_p[i]._w), &(w[i]), sizeof(double *), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy1 fail");
}
这些cudaMemcpy
操作仍然必须单独完成。