MPI_Isend和MPI_Irecv似乎导致死锁

时间:2011-04-07 23:06:11

标签: c mpi parallel-processing hpc openmpi

我在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。我对此代码有许多疑问/问题:

  1. 为什么最终循环的输出(打印所有数组)散布在输出的其余部分,当我在它之前有一个MPI_Barrier()以确保在打印之前完成所有工作出?

  2. 从0级发送到0级是可行/明智的 - 这样可行吗? (假设当前发布了正确的匹配接收)。

  3. 我在输出中得到了很多非常奇怪的长数字,我认为这是一些内存覆盖问题或变量大小问题。有趣的是,这必须是由MPI通信产生的,因为我将new_array初始化为值9999.99并且通信显然导致它被更改为这些奇怪的值。有什么想法吗?

  4. 总的来说,似乎有些换位正在发生(矩阵的位似乎是换位的......),但绝对不是全部 - 这些正在出现的奇怪数字让我最担心! / p>

1 个答案:

答案 0 :(得分:4)

使用MPI_IsendMPI_Irecv时,您必须确保在等待请求完成之前不修改缓冲区,并且您肯定违反了此规则。如果您将所有收据全部放入第二个矩阵而不是在适当的位置怎么办?

此外,global_x2 * global_y2是您的标记,但我不确定它对每个发送 - 接收对都是唯一的,这可能会搞砸了。如果您将其切换为发送代码(global_y2 * global_columns) + global_x2并收到代码(global_x2 * global_columns) + global_y2,会发生什么情况。

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