【问题标题】:Segmentation Fault using MPI_Sendrecv with a 2D contiguous array使用带有 2D 连续数组的 MPI_Sendrecv 的分段错误
【发布时间】:2012-12-17 05:57:03
【问题描述】:

我的问题很简单。当使用 MPI_Sendrecv 时,它会系统地生成一个段错误。我之前在使用 2D 数组和基本的 MPI_Send 时遇到了同样的问题,但最终解决了。当我尝试在最后一种情况下使用相同的解决方案时,这并没有改变任何东西。因此,我正在寻求帮助!

所以基本上,我通过这段代码分配我的所有矩阵:

    double**
    allocateMatrix(int rows, int cols)
    {
        double **M; // Row pointer
        double *Mdata; // Where data will be actually storde

        M = calloc(rows, sizeof *M);
        Mdata = calloc(rows*cols, sizeof(double));

        int i;
        for (i = 0; i < rows; ++i) 
            M[i] = Mdata+ i*rows;

        return M;
    }

我这样做是因为我读到 MPI_Sendrecv 不应该处理非连续数据...

这是我得到错误的地方:

    double **submtx;
    submtx = allocateMatrix(submtx_dim, submtx_dim);

    /* 
    ...
    */

    MPI_Sendrecv(&(submtx[0][0]), 1, left_col, neighbours[0], LEFT_COL,
                 &tmp_rcol, SUB_MTX_SIZE, MPI_DOUBLE, neighbours[0], RIGHT_COL,
                 my_grid, MPI_STATUS_IGNORE);

我知道它测试错误来自给 MPI_Sendrecv 的第一个参数的语法。我使用 MPI 子数组和一个网格加上一个 shift 来让我的邻居在网格上,但是这个代码已经在一个基本版本上工作,分别使用 Send/Recv。唯一的变化是用 MPI_Sendrecv 调用替换了 Send/recv 调用,以简化代码......所以我认为不需要整个代码。

有什么想法吗?

我试过了:

    MPI_Sendrecv(&submtx, ...
    MPI_Sendrecv(submtx, ...

这些都不起作用,我仍然在这条线上遇到分段错误。

【问题讨论】:

  • M = calloc(rows, sizeof *M);(但在您的特定平台上,指针和双精度值的大小可能相同。
  • 哦,是的,确实是的...好吧,它没有改变任何东西,因为它们的大小相同,但无论如何这是一个相当大的错误,所以谢谢=)
  • 我的答案中的表格不太容易出错。 (因为 *M 直接从预期对象获取 sizeof 信息)它适用于任何类型。
  • 是的,你是对的,这就是我想在上面的评论中说的,即使它在这种情况下有效,也是一个错误。

标签: c multidimensional-array segmentation-fault mpi


【解决方案1】:

MPI_Sendrecv 需要一个指向数据缓冲区的指针作为第一个参数 (void *)

http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Sendrecv.html

所以,试试这个

double* // pointer to double (not pointer to pointer)
    allocateMatrix(int rows, int cols)
    {
        return calloc(rows * cols, sizeof(double));
    }

后来

double *submtx;
submtx = allocateMatrix(submtx_dim, submtx_dim);

/* 
...
*/

MPI_Sendrecv(submtx,....

我想评论区在矩阵中写入了一些东西......

要访问 r 行和 c 列中的值,请执行此操作

smbmtx[c + r * submtx_dim] = 1.234;

【讨论】:

  • 我的实际函数分配一个连续的内存块并返回一个指针指针以二维方式访问它,以简化此过程。修改它以返回双指针不是我正在寻找的答案......虽然它可以解决问题,但它也要求我更改几乎所有代码以适应可能以另一种方式修复的特定问题。据我了解这种语法“&(submtx[0][0])”,它当前将地址返回到我分配的这个连续矩阵的开头,就像在您的解决方案中使用“submtx”一样对吧?
【解决方案2】:

事实证明,我摆脱了分段错误。我的问题中写的语法实际上很好,&(submtx[0][0]) 不是问题……正如这篇文章中指出的那样,submtx[0] 也可以正常工作(MPI_Type_create_subarray and MPI_Send)。

这实际上有点棘手,因为根本没有真正的问题,只是我必须在真正的问题之前做一些愚蠢的事情:

不工作的代码:

    MPI_Barrier(my_grid);

    do {

        MPI_Sendrecv(&(submtx[0][0], ...)

        /*
        ...
        */

    } while (cond);

和工作代码:

    MPI_Barrier(my_grid);

    double *stupid_allocation;
    stupid_allocation = calloc(submtx_dim*submtx_dim, sizeof(double));

    do {

        MPI_Sendrecv(&(submtx[0][0]), ...)

        /*
        ...
        */

    } while (cond);

虽然我很高兴我的问题终于得到解决,但我真的很想得到这个问题的答案,这意味着“为什么在删除一个分配(或我认为的其他任何东西)时它不起作用有什么用??

【讨论】:

  • 这种行为几乎总是某处缓冲区溢出的迹象。是时候打破像 valgrind 这样的工具,看看出了什么问题。
  • 没有明显的解决办法,我用 valgrind 检查了 memcheck 产生的调试文件,里面没有出现“after”和“before”这两个词,所以我不这么认为是缓冲区溢出。但我绝对不是 valgrind 战士,所以无论如何我还是朝着那个方向前进……
  • Valgrind 仍然给我很多错误,但似乎所有这些都是由于 MPI_Init 使用未初始化的值以及释放我的特定数据类型(由 MPI_Type_create_subarray 创建),这似乎是释放时也未初始化(我确实提交了它们)...
猜你喜欢
  • 1970-01-01
  • 2021-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-22
  • 2021-03-26
  • 1970-01-01
相关资源
最近更新 更多