Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ cudaMemcpy分段故障_C++_Cuda_Segmentation Fault - Fatal编程技术网

C++ cudaMemcpy分段故障

C++ cudaMemcpy分段故障,c++,cuda,segmentation-fault,C++,Cuda,Segmentation Fault,我已经被这个错误困扰了很长一段时间,所以我决定把它贴在这里 调用cudaMemcpy时发生此分段错误: CurrentGrid->cdata[i] = new float[size]; cudaMemcpy(CurrentGrid->cdata[i], Grid_dev->cdata[i], size*sizeof(float),\ cudaMemcpyDeviceToHost); CurrentGrid和Grid\u dev分别是主机和设备上

我已经被这个错误困扰了很长一段时间,所以我决定把它贴在这里

调用cudaMemcpy时发生此分段错误:

CurrentGrid->cdata[i] = new float[size];
cudaMemcpy(CurrentGrid->cdata[i], Grid_dev->cdata[i], size*sizeof(float),\
                cudaMemcpyDeviceToHost);
CurrentGrid
Grid\u dev
分别是主机和设备上的
Grid
类对象的指针,在此上下文中i=0。类成员cdata是浮点型指针数组。为了进行调试,在调用cudaMemcpy之前,我打印出了
Grid\u Dev->cdata[I]
的每个元素的值,以及
CurrentGrid->cdata[I]
Grid\u Dev->cdata[I]
的地址和
size
的值,看起来都不错。但它仍然以“分段错误(堆芯转储)”结束,这是唯一的错误消息。cuda memcheck仅给出“进程未成功终止”。我目前无法使用cuda gdb。关于去哪里有什么建议吗

更新:现在我似乎已经解决了这个问题,我在设备上用另一个浮点指针cudaMalloc,然后将Grid\u dev->cdata[I]的值CUDAMMCPY到A,然后将CUDAMMCPY到主机。 因此,上面编写的代码段变成:

float * A;
cudaMalloc((void**)&A, sizeof(float));
...
...
cudaMemcpy(&A, &(Grid_dev->cdata[i]), sizeof(float *), cudaMemcpyDeviceToHost);    
CurrentGrid->cdata[i] = new float[size];
cudaMemcpy(CurrentGrid->cdata[i], A, size*sizeof(float), cudaMemcpyDeviceToHost);            
我这样做是因为valgrind弹出了“大小为8的无效读取”,我认为这是指
Grid\u dev->cdata[I]
。我用gdb再次检查了它,打印出
Grid\u dev->cdata[I]
的值为空。因此,我想即使在这个cudaMemcpy调用中,我也不能直接取消对设备指针的引用。但是为什么呢?根据本文底部的注释,我们应该能够在cudaMemcpy函数中取消对设备指针的引用

另外,我不知道cudamaloc和cudaMemcpy如何工作的潜在机制,但我认为通过cudamaloc一个指针,比如这里的a,我们实际上分配这个指针指向设备上的某个地址。通过cudaMemcpy将
Grid\u dev->cdata[i]
分配给A,就像上面修改的代码一样,我们将指针A重新分配给数组。那么,我们是不是忘记了A在添加地址时指向的上一个地址?这是否会导致内存泄漏或其他问题?如果是,我应该如何正确处理这种情况? 谢谢

为了便于参考,我将发生此错误的完整函数的代码放在下面

非常感谢

__global__ void Print(grid *, int);
__global__ void Printcell(grid *, int);
void CopyDataToHost(param_t p, grid * CurrentGrid, grid * Grid_dev){

    cudaMemcpy(CurrentGrid, Grid_dev, sizeof(grid), cudaMemcpyDeviceToHost);
#if DEBUG_DEV
    cudaCheckErrors("cudaMemcpy1 error");
#endif
    printf("\nBefore copy cell data\n");
    Print<<<1,1>>>(Grid_dev, 0);            //Print out some Grid_dev information for 
    cudaDeviceSynchronize();                //debug 
    int NumberOfBaryonFields = CurrentGrid->ReturnNumberOfBaryonFields();
    int size = CurrentGrid->ReturnSize();
    int vsize = CurrentGrid->ReturnVSize();
    CurrentGrid->FieldType = NULL;
    CurrentGrid->FieldType = new int[NumberOfBaryonFields];
    printf("CurrentGrid size is %d\n", size);
    for( int i = 0; i < p.NumberOfFields; i++){
        CurrentGrid->cdata[i] = NULL;
        CurrentGrid->vdata[i] = NULL;
        CurrentGrid->cdata[i] = new float[size];
        CurrentGrid->vdata[i] = new float[vsize];

        Printcell<<<1,1>>>(Grid_dev, i);//Print out element value of Grid_dev->cdata[i]
        cudaDeviceSynchronize();        

        cudaMemcpy(CurrentGrid->cdata[i], Grid_dev->cdata[i], size*sizeof(float),\
                cudaMemcpyDeviceToHost);               //where error occurs
#if DEBUG_DEV
        cudaCheckErrors("cudaMemcpy2 error");
#endif
        printf("\nAfter copy cell data\n");
        Print<<<1,1>>>(Grid_dev, i);
        cudaDeviceSynchronize();
        cudaMemcpy(CurrentGrid->vdata[i], Grid_dev->vdata[i], vsize*sizeof(float),\
                cudaMemcpyDeviceToHost);
#if DEBUG_DEV
        cudaCheckErrors("cudaMemcpy3 error");
#endif
    }
    cudaMemcpy(CurrentGrid->FieldType, Grid_dev->FieldType,\
            NumberOfBaryonFields*sizeof(int), cudaMemcpyDeviceToHost);
#if DEBUG_DEV
    cudaCheckErrors("cudaMemcpy4 error");
#endif
}

我相信我知道问题出在哪里,但为了证实这一点,查看用于在设备上设置
Grid\u dev
类的代码将非常有用

当一个类或其他数据结构要在设备上使用时,并且该类中有指向内存中其他对象或缓冲区的指针(对于将在设备上使用的类,可能在设备内存中),则使该顶级类在设备上可用的过程变得更加复杂

假设我有一个这样的类:

class myclass{
  int myval;
  int *myptr;
  }
我可以在主机上实例化上述类,然后
malloc
一个
int
数组,并将该指针指定给
myptr
,一切都会很好。为了使该类仅在设备上可用,该过程可以类似。我可以:

  • cudaMalloc指向设备内存的指针,该内存将保存
    myclass
  • (可选)使用cudaMemcpy将主机上的
    myclass
    实例化对象从步骤1复制到设备指针
  • 在设备上,使用
    malloc
    new
    myptr
  • 如果我不想访问主机上为
    myptr
    分配的存储,那么上面的顺序就可以了。但如果我确实希望从主机上看到该存储,我需要一个不同的序列:

  • cudamaloc是一个指向设备内存的指针,它将保存
    myclass
    ,我们称之为
    mydevobj
  • (可选)使用cudaMemcpy从步骤1将主机上的
    myclass
    实例化对象复制到设备指针
    mydevobj
  • 在主机上创建一个单独的int指针,我们称之为
    myhostptr
  • cudamaloc
    int
    存储在设备上,用于
    myhostptr
  • CUDAMEMCP将主机的
    myhostptr
    指针值移动到设备指针
    &(mydevobj->myptr)
  • 之后,您可以
    cudaMemcpy
    将嵌入指针
    myptr
    指向的数据
    myptr
    分配到
    myhostptr
    上的区域(通过
    cudamaloc

    请注意,在步骤5中,由于我正在获取此指针位置的地址,因此此cudaMemcpy操作只需要主机上的
    mydevobj
    指针,该指针在cudaMemcpy操作中有效(仅限)

    然后将正确设置设备指针的值
    myint
    ,以执行您尝试执行的操作。然后,如果您想将数据从
    myint
    发送到主机,则可以在任何cudaMemcpy调用中使用指针
    myhostptr
    ,而不是
    mydevobj->myptr
    。如果我们尝试使用
    mydevobj->myptr
    ,则需要取消引用
    mydevobj
    ,然后使用它检索存储在
    myptr
    中的指针,然后将该指针用作指向/来自位置的副本。这在主机代码中是不可接受的。如果你尝试这样做,你会得到一个seg故障。(请注意,作为类比,my
    MyDevBj
    类似于您的
    Grid\u dev
    ,my
    myptr
    类似于您的
    cdata

    总的来说,这是一个概念,在你第一次遇到它时需要仔细思考,所以像这样的问题会出现一些频率。您可能希望研究其中一些问题以查看代码示例(因为您尚未提供设置
    Grid\u dev
    )的代码:


  • 分段故障意味着主机代码内存访问问题。您不需要cuda memcheck或cuda gdb来诊断根本原因。标准主机调试器或内存分析
    class myclass{
      int myval;
      int *myptr;
      }