【问题标题】:MPI_Waitany causes segmentation faultMPI_Waitany 导致分段错误
【发布时间】:2014-09-10 20:16:16
【问题描述】:

我正在使用 MPI 将图像分发到不同的进程,以便:

  1. 进程 0 将图像分发到不同的进程。

  2. 处理其他 than 0 处理图像,然后将结果发送回进程 0。

进程 0 会在进程完成处理图像的工作时尝试使进程忙碌,因此一旦它空闲,就会为其分配另一个图像来处理。代码如下:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "mpi.h"

#define MAXPROC 16    /* Max number of processes */
#define TOTAL_FILES 7

int main(int argc, char* argv[]) {
        int i, nprocs, tprocs, me, index;
        const int tag  = 42;    /* Tag value for communication */

        MPI_Request recv_req[MAXPROC];  /* Request objects for non-blocking receive */
        MPI_Request send_req[MAXPROC]; /* Request objects for non-blocking send */     
        MPI_Status status;              /* Status object for non-blocing receive */

        char myname[MPI_MAX_PROCESSOR_NAME];             /* Local host name string */
        char hostname[MAXPROC][MPI_MAX_PROCESSOR_NAME];  /* Received host names */
        int namelen;   

        MPI_Init(&argc, &argv);                /* Initialize MPI */
        MPI_Comm_size(MPI_COMM_WORLD, &nprocs);    /* Get nr of processes */
        MPI_Comm_rank(MPI_COMM_WORLD, &me);    /* Get own identifier */

        MPI_Get_processor_name(myname, &namelen);  /* Get host name */
        myname[namelen++] = (char)0;              /* Terminating null byte */

        /* First check that we have at least 2 and at most MAXPROC processes */
        if (nprocs<2 || nprocs>MAXPROC) {
                if (me == 0) {
                  printf("You have to use at least 2 and at most %d processes\n", MAXPROC);
                }
                MPI_Finalize(); exit(0);
        }

        /* if TOTAL_FILES < nprocs then use only TOTAL_FILES + 1 procs */
        tprocs = (TOTAL_FILES < nprocs) ? TOTAL_FILES + 1 : nprocs;
        int done = -1;

        if (me == 0) {    /* Process 0 does this */

                int send_counter = 0, received_counter;

                for (i=1; i<tprocs; i++) {
                        MPI_Isend(&send_counter, 1, MPI_INT, i, tag, MPI_COMM_WORLD, &send_req[i]);
                        ++send_counter;
                        /* Receive a message from all other processes */
                        MPI_Irecv (hostname[i], namelen, MPI_CHAR, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &recv_req[i]);
                }      

                for (received_counter = 0; received_counter < TOTAL_FILES; received_counter++){

                        /* Wait until at least one message has been received from any process other than 0*/
                        MPI_Waitany(tprocs-1, &recv_req[1], &index, &status);

                        if (index == MPI_UNDEFINED) perror("Errorrrrrrr");                     
                        printf("Received a message from process %d on %s\n", status.MPI_SOURCE, hostname[index+1]);

                        if (send_counter < TOTAL_FILES){ /* si todavia faltan imagenes por procesar */
                                MPI_Isend(&send_counter, 1, MPI_INT, status.MPI_SOURCE, tag, MPI_COMM_WORLD, &send_req[status.MPI_SOURCE]);
                                ++send_counter;
                                MPI_Irecv (hostname[status.MPI_SOURCE], namelen, MPI_CHAR, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &recv_req[status.MPI_SOURCE]);
                        }      
                }

              for (i=1; i<tprocs; i++) {
                      MPI_Isend(&done, 1, MPI_INT, i, tag, MPI_COMM_WORLD, &send_req[i]);
              }

        } else if (me < tprocs) { /* all other processes do this */

                int y;         
                MPI_Recv(&y, 1, MPI_INT, 0,tag,MPI_COMM_WORLD,&status);

                while (y != -1) {                                      
                        printf("Process %d: Received image %d\n", me, y);
                        sleep(me%3+1);  /* Let the processes sleep for 1-3 seconds */

                        /* Send own identifier back to process 0 */
                        MPI_Send (myname, namelen, MPI_CHAR, 0, tag, MPI_COMM_WORLD);
                        MPI_Recv(&y, 1, MPI_INT, 0,tag,MPI_COMM_WORLD,&status);                
                }      
        }

        MPI_Finalize();
        exit(0);
}

这是基于this 示例。

现在我遇到了一个分段错误,不知道为什么。我对 MPI 还很陌生,但我在上面的代码中看不到错误。它只发生在一定数量的进程中。例如,当 TOTAL_FILES = 7 并且使用 5、6 或 7 个进程运行时。可在 9 个或以上进程中正常工作。

完整的代码可以在here找到。尝试使用 6 个进程会导致上述错误。

编译和执行:

mpicc -Wall sscce.c -o sscce -lm 
mpirun -np 6 sscce

【问题讨论】:

  • 您能创建一个sscce.org 以便我们帮助调试您的代码吗?
  • @WesleyBland 我的代码很大程度上基于上面链接的示例代码。尝试编辑以使其成为 sscce。如果这对你来说还不够,请告诉我
  • 这里仍然没有SSCCE。甚至没有main 函数。你没看网站吗?

标签: c segmentation-fault mpi openmpi


【解决方案1】:

导致分段错误的不是MPI_Waitany,而是当recv_req[] 中的所有请求都完成时(即index == MPI_UNDEFINED),您处理这种情况的方式。 perror() 不会停止代码,它会继续运行,然后在尝试访问 hostname[index+1] 时出现 printf 语句中的段错误。数组中所有请求都完成的原因是由于在接收调用中使用了MPI_ANY_SOURCE,因此不能保证发送方的排名等于recv_req[] 中的请求索引 - 只需比较@987654329 @ 和status.MPI_SOURCEMPI_Waitany 返回后亲自查看。因此,随后对MPI_Irecv 的调用很可能会覆盖仍未完成的请求,因此MPI_Waitany 可以完成的请求数少于预期的实际结果数。

另请注意,您从不等待发送请求完成。您很幸运,Open MPI 实现使用了一个 Eager 协议来发送小消息,因此即使在启动的发送请求上从未调用过 MPI_Wait(any|all)MPI_Test(any|all) 也会发送这些消息。

【讨论】:

  • 确实,这就是问题所在。但问题是:如果我使用 MPI_Isend,然后是 MPI_Irecv,然后是 Wait for the recv,我还应该使用 MPI_Wait 进行发送吗?为什么?如果我收到来自某个进程的响应,则表示该请求已发送,该进程收到该请求,对其进行处理并做出响应...
  • MPI 标准要求由MPI_IsendMPI_Irecv 发起的请求应通过调用MPI_Wait 或重复调用MPI_Test 来适当地完成,直到它返回一个肯定的测试结果。甚至允许 MPI 实现推迟数据传输,直到进行那些等待/测试调用,并且许多实现在发送大消息时这样做。在您的情况下,它之所以起作用,仅仅是因为使用了一种称为急切发送的性能技巧。否则您的应用程序不合格。
  • 此外,不完成未完成的请求会导致内存泄漏,并且由于库必须遍历不断增长的请求队列,因此某些 MPI 实现可能会导致通信显着减慢。
  • 感谢您的意见。这对更好地理解 MPI 非常有帮助。
猜你喜欢
  • 1970-01-01
  • 2011-11-06
  • 2020-12-31
  • 2019-07-21
  • 2018-07-28
  • 2014-04-25
  • 2011-07-18
  • 2013-02-26
  • 2022-01-12
相关资源
最近更新 更多