我想知道是否有人可以为我介绍MPI_Waitall函数。我有一个程序使用MPI_Isend和MPI_Irecv传递信息。完成所有发送和接收后,程序中的一个进程(在本例中为进程0)将打印一条消息。我的Isend/Irecv正在运行,但是消息在程序中的某个随机点打印出来;因此,我尝试使用MPI_Waitall等到所有请求完成后再打印消息。我收到以下错误消息:
Fatal error in PMPI_Waitall: Invalid MPI_Request, error stack:
PMPI_Waitall(311): MPI_Waitall(count=16, req_array=0x16f70d0, status_array=0x16f7260) failed
PMPI_Waitall(288): The supplied request in array element 1 was invalid (kind=0)
这是一些相关的代码:
MPI_Status *status;
MPI_Request *request;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
status = (MPI_Status *) malloc(numtasks * sizeof(MPI_Status));
request = (MPI_Request *) malloc(numtasks * sizeof(MPI_Request));
/* Generate Data to send */
//Isend/Irecvs look like this:
MPI_Isend(&data, count, MPI_INT, dest, tag, MPI_COMM_WORLD, &request[taskid]);
MPI_Irecv(&data, count, MPI_INT, source, tag, MPI_COMM_WORLD, &request[taskid]);
MPI_Wait(&request[taskid], &status[taskid]
/* Calculations and such */
if (taskid == 0) {
MPI_Waitall (numtasks, request, status);
printf ("All done!\n");
}
MPI_Finalize();
在没有调用MPI_Waitall的情况下,程序可以正常运行,但是“所有完成”消息将在进程0的Isend/Irecv消息完成后立即打印,而不是在所有Isend/Irecvs完成后立即打印。
感谢您提供任何帮助。
最佳答案
您只需要设置request
数组的一个元素,即request[taskid]
(通过您用接收一个覆盖发送请求句柄的方式,就不可避免地丢失了前一个)。请记住,MPI用于对分布式内存机器进行编程,并且每个MPI进程都有其自己的request
数组副本。在等级taskid
中设置一个元素不会神奇地将值传播到其他等级,即使这样做,请求也仅具有局部有效性。正确的实现是:
MPI_Status status[2];
MPI_Request request[2];
MPI_Init(&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &taskid);
MPI_Comm_size (MPI_COMM_WORLD, &numtasks);
/* Generate Data to send */
//Isend/Irecvs look like this:
MPI_Isend (&data, count, MPI_INT, dest, tag, MPI_COMM_WORLD, &request[0]);
// ^^^^
// ||
// data race !!
// ||
// vvvv
MPI_Irecv (&data, count, MPI_INT, source, tag, MPI_COMM_WORLD, &request[1]);
// Wait for both operations to complete
MPI_Waitall(2, request, status);
/* Calculations and such */
// Wait for all processes to reach this line in the code
MPI_Barrier(MPI_COMM_WORLD);
if (taskid == 0) {
printf ("All done!\n");
}
MPI_Finalize();
顺便说一句,您的代码中存在数据争用。
MPI_Isend
和MPI_Irecv
都使用相同的数据缓冲区,这是不正确的。如果您只是尝试将data
的内容发送到dest
,然后从source
接收到它,那么请改用MPI_Sendrecv_replace
,并忽略非阻塞操作:MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &taskid);
MPI_Comm_size (MPI_COMM_WORLD, &numtasks);
/* Generate Data to send */
MPI_Sendrecv_replace (&data, count, MPI_INT, dest, tag, source, tag,
MPI_COMM_WORLD, &status);
/* Calculations and such */
// Wait for all processes to reach this line in the code
MPI_Barrier(MPI_COMM_WORLD);
if (taskid == 0) {
printf ("All done!\n");
}
MPI_Finalize();