【问题标题】:MPI message received in different communicator在不同的通信器中收到 MPI 消息
【发布时间】:2014-07-11 13:23:14
【问题描述】:

据我了解,MPI 传播者限制了传播范围,例如 从一个通信器发送的消息永远不会在另一个通信器中接收。

但是,下面内联的程序似乎与此相矛盾。

我知道MPI_Send 调用会在匹配接收发布之前返回,因为它在后台进行了内部缓冲(与MPI_Ssend 不同)。我也知道MPI_Comm_free 不会立即销毁通信器,而只是将其标记为释放并等待任何待处理的操作完成。我想我不匹配的发送操作将永远挂起,但是我想知道为什么相同的对象(整数值)会被第二个通信器重用!?

这是正常行为,是 MPI 库实现中的错误,还是我的程序不正确?

非常感谢任何建议!

后期编辑:发布follow-up question


#include "stdio.h"
#include "unistd.h"
#include "mpi.h"

int main(int argc, char* argv[]) {
    int  rank, size;
    MPI_Group group;
    MPI_Comm my_comm;

    MPI_Init(&argc, &argv);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_group(MPI_COMM_WORLD, &group);

    MPI_Comm_create(MPI_COMM_WORLD, group, &my_comm);
    if (rank == 0) printf("created communicator %d\n", my_comm);

    if (rank == 1) {
        int msg = 123;
        MPI_Send(&msg, 1, MPI_INT, 0, 0, my_comm);
        printf("rank 1: message sent\n");
    }

    sleep(1);
    if (rank == 0) printf("freeing communicator %d\n", my_comm);
    MPI_Comm_free(&my_comm);

    sleep(2);

    MPI_Comm_create(MPI_COMM_WORLD, group, &my_comm);
    if (rank == 0) printf("created communicator %d\n", my_comm);

    if (rank == 0) {
        int msg;
        MPI_Recv(&msg, 1, MPI_INT, 1, 0, my_comm, MPI_STATUS_IGNORE);
        printf("rank 0: message received\n");
    }

    sleep(1);
    if (rank == 0) printf("freeing communicator %d\n", my_comm);
    MPI_Comm_free(&my_comm);

    MPI_Finalize();
    return 0;
}

输出:

created communicator -2080374784
rank 1: message sent
freeing communicator -2080374784
created communicator -2080374784
rank 0: message received
freeing communicator -2080374784

【问题讨论】:

  • 有趣 - 我注意到这在 OpenMPI 中的行为不同。我不确定这本身是一个错误,还是未定义行为的结果(例如,我不清楚释放带有该 Send 的通信器是否有效,但显然仍在飞行中)。重新使用通信器的整数表示并不意味着太多。这只是一个不透明对象的句柄。重新使用它类似于(我希望,非常类似于)重新使用最近被释放的表条目。
  • 不出所料,在 IntelMPI 和 mvapich2 下,当使用 Ssend 或大于急切限制的消息时,该程序正确挂在 rank 1 的发送。据推测,当 my_comm 急切发送时,MPICH2 不会将 my_comm 上的发送视为“待处理”,因此继续并释放 my_comm(OMPI 在 comm_free 处挂起)。但我不知道由此产生的意外结果是否是(a)由于用户代码中无效的提前释放通信器而导致的未定义行为(例如,在您知道它已被接收之前修改发送缓冲区),(b)不正确的 MPICH2 行为,或 (c) 标准中的真正歧义。
  • ..我的错误;在 OpenMPI 中,它挂在接收端。
  • 这可能是 MPICH(英特尔 MPI 所基于)中的一个错误。你能把这个例子报告给discuss@mpich.org吗?
  • @kraffenetti - 谢谢!我不知道英特尔 MPI 是基于 MPICH 的。我会尝试在那里报告。

标签: mpi intel-mpi


【解决方案1】:

您看到的数字只是通讯器的句柄。释放手柄后,可以安全地重复使用它。至于为什么你能够发送消息,看看你是如何创建通信器的。当您使用 MPI_Comm_group 时,您将获得一个包含与指定通信器关联的等级的组。在这种情况下,您将获得所有排名,因为您获得的是 MPI_COMM_WORLD 的组。然后,您将使用 MPI_Comm_create 创建基于一组等级的通信器。您正在使用刚刚获得的同一组,其中将包含所有等级。因此,您的新通信器具有 MPI_COMM_WORLD 的所有等级。如果您希望您的通信器仅包含等级的子集,则需要使用不同的函数(或多个函数)来创建所需的组。我建议通读 MPI 标准的第 6 章,它包含您需要的所有功能。选择你需要什么来构建你想要的沟通器。

【讨论】:

  • 同意句柄,但我不认为这对传播者是正确的。如果通信者具有相同的组和等级,则它们是一致的,但它们不是相同的通信者(例如,执行MPI_COMM_COMPARE 返回MPI_CONGRUENT,而不是@987654324 @)。所以创建一个MPI_COMM_WORLD 的副本,发送给它,然后在接收端从MPI_COMM_WORLD 执行MPI_Recv() 不应该(也不)工作。
  • 有意使用与 MPI_COMM_WORLD 相同的进程组创建新的通信器。这是我在更复杂的多线程应用程序中面临的问题的简化重现,我们在每个线程中使用一个通信器,以确保仅接收从某个节点上的线程 i 发送的消息通过其他节点上的线程i
  • @i.adri,我建议改用 MPI 标签。重量更轻,发送/接收对必须有匹配的标签。只需使用标签的线程号。
  • 我们在 MPICH trac 上为此问题创建了票证 2096。 trac.mpich.org/projects/mpich/ticket/2096如果您想加入抄送列表以获取进度更新,请告诉我。
  • @kraffenetti - 非常感谢,看起来你在那儿发帖的速度比我快。是的,如果您能将我添加到 CC 列表中,我将不胜感激。到目前为止,我看到答案是程序不正确,因此预期的行为是未定义的。但是,我仍然认为,当所有涉及的进程调用 MPI_Comm_free() 时,取消此类不匹配的发送是可取的。我将返回一个稍微详细一点的例子来解释我为什么这么认为。
猜你喜欢
  • 2013-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-06
  • 2017-12-17
  • 2016-11-19
  • 1970-01-01
  • 2021-09-13
相关资源
最近更新 更多