MPI标准3.0在第5.13节中说
最后,在多线程实现中,可以有多个, 在进程中同时执行集体通信调用。在 这些情况,是用户的责任,以确保 同一个传播者并不是由两个不同的集体同时使用的 通信呼叫在同一个过程中。
我编写了以下程序,该程序无法正确执行(但编译)并转储核心
void main(int argc, char *argv[])
{
int required = MPI_THREAD_MULTIPLE, provided, rank, size, threadID, threadProcRank ;
MPI_Comm comm = MPI_COMM_WORLD ;
MPI_Init_thread(&argc, &argv, required, &provided);
MPI_Comm_size(comm, &size);
MPI_Comm_rank(comm, &rank);
int buffer1[10000] = {0} ;
int buffer2[10000] = {0} ;
#pragma omp parallel private(threadID,threadProcRank) shared(comm, buffer1)
{
threadID = omp_get_thread_num();
MPI_Comm_rank(comm, &threadProcRank);
printf("\nMy thread ID is %d and I am in process ranked %d", threadID, threadProcRank);
if(threadID == 0)
MPI_Bcast(buffer1, 10000, MPI_INTEGER, 0, comm);
If (threadID == 1)
MPI_Bcast(buffer1, 10000, MPI_INTEGER, 0, comm);
}
MPI_Finalize();
}
我的问题是:每个进程中有两个线程,网络ID为0,线程ID为1,广播调用可以作为根进程中的MPI_Send()(即进程0)。我将它解释为MPI_Send()的两个循环,其中目标是剩余的进程。目标进程还在线程ID 0和线程ID 1中发布MPI_Bcast()。这些可以作为两个线程中的每个进程发布的两个MPI_Recv()。由于MPI_Bcast()是相同的 - 在接收进程0(根)发送的消息时应该没有匹配问题。但是程序仍然不起作用。为什么?是因为消息可能在同一个通信器上的不同/相同集体上混淆了吗?而且由于MPI(mpich2)看到了这种可能性,它只是不允许同一个通信器上的两个集体同时待定?
答案 0 :(得分:4)
首先,您没有检查MPI实现返回实际提供的线程支持级别的provided
的值。该标准允许此级别低于请求的级别,而正确的MPI应用程序宁愿执行以下操作:
MPI_Init_thread(&argc, &argv, required, &provided);
if (provided < required)
{
printf("Error: MPI does not provide the required thread support\n");
MPI_Abort(MPI_COMM_WORLD, 1);
exit(1);
}
其次,这行代码是多余的:
MPI_Comm_rank(comm, &threadProcRank);
MPI中的主题不具有单独的排名 - 只有进程具有排名。有人建议在MPI 3.0中引入所谓的端点,这样就可以让单个进程拥有多个级别,并将它们绑定到不同的线程但是它没有成功进入标准的最终版本。
第三,您在两个集合中使用相同的缓冲区变量。我想你的意图是在线程0的调用中使用buffer1
,在线程1的调用中使用buffer2
。MPI_INTEGER
是与Fortran中的INTEGER
对应的数据类型。对于C int
类型,相应的MPI数据类型为MPI_INT
。
第四,将MPI_BCAST
解释为MPI_SEND
和相应的MPI_RECV
的循环只是一种解释。实际上,实施方式有很大不同 - 请参阅here。例如,对于较小的消息,其中初始网络设置等待时间远高于物理数据传输时间,使用二进制和二叉树以便最小化集合的等待时间。较大的消息通常被分成许多段,然后使用管道将段从根级别传递给所有其他段。即使在树分布情况下,消息仍然可以被分段。
实际上,实际上每个集合操作都是使用具有相同标记的消息实现的,通常带有负标记值(应用程序员不允许使用这些标记值)。这意味着在你的情况下,两个MPI_Bcast
调用将使用相同的标签来传输他们的消息,并且因为排名是相同的并且通信器是相同的,所以消息将被混淆。因此,要求仅在单独的传播者上进行并发集体。
程序崩溃有两个原因。原因之一是MPI库不提供MPI_THREAD_MULTIPLE
。第二个原因是如果消息被分成两个不均匀大小的块,例如,较大的第一部分和较小的第二部分。两个集合调用之间的干扰可能导致第二个线程在等待第二个较小的块时接收指向第一个线程的大的第一个块。结果将是消息截断,并且将调用中止MPI错误处理程序。这通常不会导致段错误和核心转储,所以我认为你的MPICH2根本不是编译为线程安全的。
这不是MPICH2特有的。 Open MPI和其他实现也容易受到相同的限制。