MPI倍数Isends,Irecvs与waitany是一个很好的方法?

时间:2015-12-13 15:06:59

标签: mpi deadlock

在MPI项目中使用以下代码有什么问题吗?它可能会产生死锁或缓冲区重叠吗?

//send a data to all nodes on receiver list
for (auto &e : receivers_list) {
        MPI_Request request;
        MPI_Isend( &data, 1, MPI_INT, e.remot_id , 1234 , MPI_COMM_WORLD, &request);
}

//read data from senders
MPI_Request request_arr[senders_list.size()];
for (auto &e : senders_list) {
        MPI_Irecv  (&data, 1, MPI_INT, e.remot_id, MPI_ANY_TAG, MPI_COMM_WORLD, &request_arr[request_index++]);
}

//wait for all receives complete 
for (int count_recv = 0; count_recv < senders_list.size(); ++count_recv) {
        MPI_Waitany(senders_list.size(), request_arr, &request_index, MPI_STATUS_IGNORE);

     //do some code here ....
}

1 个答案:

答案 0 :(得分:1)

您发布的代码段中存在一些问题,我将在此处详细说明:

  • 非阻塞发送和接收呼叫使用相同的data缓冲区。这是非常非常错误的,这有两个层面:
    1. 由于调用是在循环内进行的,因此每个新调用都会在同一个内存地址上创建另一个读取或写入。然后,你将有足够的竞争条件,这些条件将完成这些,导致未定义的行为。
    2. 即使上述问题本身并不是问题,MPI标准明确规定访问用于非阻塞MPI通信的通信缓冲区,在此之前已经证明已完成({{1} }或MPI_Wait()等)是被禁止的。实际上,这几乎是一种防止我的第一点所描述的竞争条件的方法,但这意味着代码不仅是未定义的行为,从MPI标准的角度来看也是错误的。
  • 您在第一个循环中调用MPI_Test()始终重用相同的MPI_Isend(),在每次迭代时覆盖其值。这意味着您在前一次调用时丢失了任何句柄,从而阻止您强制完成它们,并可能泄漏MPI库中的内存。您应该使用一组请求,就像在接收循环中一样。
  • 为了处理请求,您还应该包括发送部分,以确保通信的发送方和接收方均等进展...
  • 最后,这是一个有争议的细节,通常在发送接收请求之前发布接收请求,以使MPI库准备好接收传入消息而不是处理意外的消息,从而提高性能。因此,交换发送和接收循环可能是一个好主意。

这就是代码的样子:

request