我正在尝试弄清楚为什么下面的代码偶尔会截取死锁。在2进程上运行时,每个进程启动与另一个进程的异步发送和接收。但是,两个进程上的调用次数是不同的(num_iters)。为了匹配未完成的消息,在for循环结束时,每个进程都会检查发送或接收是否正在进行,如果没有,则启动匹配的消息。最后,每个进程等待匹配的通信。为什么代码偶尔会死锁?(它已经用OpenMPI和MPICH进行了测试)
MPI_Init(&argc, &argv);
int procs;
MPI_Comm_size(MPI_COMM_WORLD, &procs);
if (procs != 2) {
std::cout << "Runs with 2 processes!";
MPI_Abort(MPI_COMM_WORLD, 1);
}
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int buffer_size = 10;
std::vector<double> snd_buffer(buffer_size, 4.2);
std::vector<double> rcv_buffer(buffer_size, 0);
MPI_Request snd_req = MPI_REQUEST_NULL;
int snd_flag;
MPI_Request rcv_req = MPI_REQUEST_NULL;
int rcv_flag;
// Asynchronously spam messages
int comm_rank = (rank + 1) % 2;
int num_iters = (rank == 0) ? 10 : 20;
for (int i = 0; i < num_iters; ++i) {
MPI_Test(&snd_req, &snd_flag, MPI_STATUS_IGNORE);
if (snd_flag != 0) {
MPI_Issend(snd_buffer.data(), buffer_size, MPI_INT, comm_rank, 0, MPI_COMM_WORLD, &snd_req);
}
MPI_Test(&rcv_req, &rcv_flag, MPI_STATUS_IGNORE);
if (rcv_flag != 0) {
MPI_Irecv(rcv_buffer.data(), buffer_size, MPI_INT, comm_rank, 0, MPI_COMM_WORLD, &rcv_req);
}
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // simulate work
}
MPI_Barrier(MPI_COMM_WORLD);
// Match outstanding messages
MPI_Test(&snd_req, &snd_flag, MPI_STATUS_IGNORE);
if (snd_flag != 0) {
MPI_Issend(snd_buffer.data(), buffer_size, MPI_INT, comm_rank, 0, MPI_COMM_WORLD, &snd_req);
}
MPI_Test(&rcv_req, &rcv_flag, MPI_STATUS_IGNORE);
if (rcv_flag != 0) {
MPI_Irecv(rcv_buffer.data(), buffer_size, MPI_INT, comm_rank, 0, MPI_COMM_WORLD, &rcv_req);
}
MPI_Wait(&rcv_req, MPI_STATUS_IGNORE);
MPI_Wait(&snd_req, MPI_STATUS_IGNORE);
MPI_Finalize();发布于 2018-08-02 06:25:01
我认为你误解了MPI_Test做什么和不做什么。它不会检查not是否有未完成的(即待定的传入)消息。(您可以使用MPI_IProbe&MPI_Test来实现这一点,但它不会真正帮助您)。相反,MPI_Test会执行检查本地操作是否已完成。这种排序之所以有效,是因为空请求句柄上的MPI_Test确实将标志设置为true。
还要注意,同步模式(MPI_Issend)并不保证接收完成,只保证接收是posted的。
在一次迭代中,您可以完成发送,但不能完成接收,反之亦然。因此,posted请求的对称性并不是可以保证死锁自由的不变量。实现死锁的实际交互有点复杂,但是您可以很容易地添加一些输出来查看发生了什么。
处理具有相互未知数量的消息的情况的通常方法是发送一个特别标记的消息,指示这是最后一条消息(即,循环完成)。您可以在消息中使用数据,也可以使用特殊标记。保证在相同的通信伙伴之间不会超越消息,这有助于您做到这一点。
https://stackoverflow.com/questions/51630686
复制相似问题