MPI_Isend 和 MPI_Irecv 似乎导致了死锁

Posted

技术标签:

【中文标题】MPI_Isend 和 MPI_Irecv 似乎导致了死锁【英文标题】:MPI_Isend and MPI_Irecv seem to be causing a deadlock 【发布时间】:2011-08-01 02:42:54 【问题描述】:

我在 MPI 中使用非阻塞通信在进程之间发送各种消息。但是,我似乎陷入了僵局。我使用 PADB (see here) 查看消息队列并得到以下输出:

1:msg12: Operation 1 (pending_receive) status 0 (pending)
1:msg12: Rank local 4 global 4
1:msg12: Size desired 4
1:msg12: tag_wild 0
1:msg12: Tag desired 16
1:msg12: system_buffer 0
1:msg12: Buffer 0xcaad32c
1:msg12: 'Receive: 0xcac3c80'
1:msg12: 'Data: 4 * MPI_FLOAT'
--
1:msg32: Operation 0 (pending_send) status 2 (complete)
1:msg32: Rank local 4 global 4
1:msg32: Actual local 4 global 4
1:msg32: Size desired 4 actual 4
1:msg32: tag_wild 0
1:msg32: Tag desired 16 actual 16
1:msg32: system_buffer 0
1:msg32: Buffer 0xcaad32c
1:msg32: 'Send: 0xcab7c00'
1:msg32: 'Data transfer completed'
--
2:msg5: Operation 1 (pending_receive) status 0 (pending)
2:msg5: Rank local 1 global 1
2:msg5: Size desired 4
2:msg5: tag_wild 0
2:msg5: Tag desired 16
2:msg5: system_buffer 0
2:msg5: Buffer 0xabbc348
2:msg5: 'Receive: 0xabd1780'
2:msg5: 'Data: 4 * MPI_FLOAT'
--
2:msg25: Operation 0 (pending_send) status 2 (complete)
2:msg25: Rank local 1 global 1
2:msg25: Actual local 1 global 1
2:msg25: Size desired 4 actual 4
2:msg25: tag_wild 0
2:msg25: Tag desired 16 actual 16
2:msg25: system_buffer 0
2:msg25: Buffer 0xabbc348
2:msg25: 'Send: 0xabc5700'
2:msg25: 'Data transfer completed'

这似乎表明发送已完成,但所有接收都处于挂起状态(以上只是标记值为 16 的日志的一小部分)。然而,这怎么可能发生呢?如果没有相关的接收完成,发送肯定无法完成,因为在 MPI 中,所有发送和接收都必须匹配。至少我是这么认为的……

谁能提供任何见解?

我可以提供我用来执行此操作的代码,但无论调用它们的顺序如何,Isend 和 Irecv 肯定都应该工作,假设 MPI_Waitall 在最后被调用。

更新:代码在this gist

更新:我对代码进行了各种修改,但仍然不能正常工作。新代码位于the same gist,我得到的输出位于this gist。我对此代码有很多疑问/问题:

    为什么当我在它之前有一个 MPI_Barrier() 以确保在打印之前完成所有工作时,最终循环的输出(打印所有数组)与其余输出穿插在一起出去了吗?

    从 0 级发送到 0 级是可能/明智的 - 可以吗? (当然,假设发布了正确匹配的接收)。

    我在输出中得到了很多非常奇怪的长数字,我认为这是某种内存覆盖问题或变量大小问题。有趣的是,这一定是由 MPI 通信引起的,因为我将 new_array 初始化为 9999.99 的值,而通信显然导致它被更改为这些奇怪的值。任何想法为什么?

总体而言,似乎发生了一些转置(矩阵的位似乎被转置了......),但绝对不是全部 - 正是这些奇怪的数字即将出现让我最担心!

【问题讨论】:

发送可以在匹配接收完成之前完成,对于非阻塞发送和接收当然是正确的。我认为这里没有任何替代方法可以查看代码。我可以想出很多方法来启动一堆 isends、irecvs,并让它们永远挂起,即使只有一个时期的发送和等待。 你的代码显然有问题,我建议你把它贴出来。 :) 感谢您的回复。该代码可在gist.github.com/909004 获得,因为它相当长,我认为其中大部分可能相当重要。它试图转置一个分布式矩阵(我知道这可能不是处理它的最佳方法,但我想让它工作)。 我现在发布了另一个更新 - 在根据以下回复的建议(以及我已经意识到的其他问题)进行修改之后。希望我们能查明真相! 【参考方案1】:

当使用MPI_IsendMPI_Irecv 时,你必须确保在等待请求完成之前不要修改缓冲区,你肯定违反了这一点。如果您将所有接收者都放入第二个矩阵而不是原地执行会怎样?

另外,global_x2 * global_y2 是您的标签,但我不确定它对于每个发送-接收对是否都是唯一的,这可能会搞砸事情。如果将其切换为发送标签(global_y2 * global_columns) + global_x2 和接收标签(global_x2 * global_columns) + global_y2,会发生什么情况。

编辑:至于您关于输出的问题,我假设您通过在同一台机器上运行所有进程并仅查看标准输出来对此进行测试。当你这样做时,你的输出会被终端奇怪地缓冲,即使 printf 代码都在屏障之前执行。我有两种方法可以解决这个问题。您可以为每个进程打印到单独的文件,也可以将输出作为消息发送到进程 0 并让他进行所有实际打印。

【讨论】:

感谢您的回复。我已经尝试过这些(我已经意识到第一个问题),但他们似乎并没有完全解决它。我现在可以在没有死锁的情况下运行它,但是换位没有正确发生。我已经更改了问题以将链接链接到代码(就像现在一样)和我得到的输出。我对一些事情有点困惑 - 我的障碍似乎没有起作用,我想知道从(例如)排名 0 到排名 0 发送一些东西并期望它工作是一个坏主意。 ..

以上是关于MPI_Isend 和 MPI_Irecv 似乎导致了死锁的主要内容,如果未能解决你的问题,请参考以下文章

MPI_Irecv 中的致命错误:正在中止作业

openmpi 中的即时通信与同步通信

InfiniBand:传输速率取决于 MPI_Test* 频率

使用 MPI (C) 交换光环/重影单元时出现未知错误

可笑的简单 MPI_Send/Recv 问题我不明白

收到的关于 MPI_Isend 的数据不一致