2

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 的两个线程发布一个广播调用,可以将其视为根进程(即进程 0)中的 MPI_Send()。我将其解释为两个 MPI_Send() 循环,其中目标是剩余进程。目标进程还在线程 ID 0 和线程 ID 1 中发布 MPI_Bcast()。这可以视为两个线程中每个进程发布的两个 MPI_Recv()。由于 MPI_Bcast() 是相同的 - 在接收进程 0(根)发送的消息时应该没有匹配问题。但是该程序仍然无法正常工作。为什么 ?是因为消息可能会在同一个通信器上的不同/相同集合中混淆吗?由于 MPI (mpich2) 看到了这种可能性,

4

1 回答 1

4

首先,您没有检查providedMPI 实现返回实际提供的线程支持级别的值。该标准允许此级别低于请求的级别,并且正确的 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 中引入所谓的端点,这将允许单个进程拥有多个等级并将它们绑定到不同的线程,但它没有成为标准的最终版本。

第三,您在两个集合中使用相同的缓冲区变量。我猜你的意图是buffer1在线程 0buffer2的调用和线程 1 的调用中使用。也是FortranMPI_INTEGER中对应的数据类型。INTEGER对于 Cint类型,对应的 MPI 数据类型是MPI_INT.

第四,MPI_BCASTas a loop of的解释MPI_SEND和对应MPI_RECV的就是——一个解释。实际上,实现有很大不同 - 请参见此处。例如,对于初始网络设置延迟远高于物理数据传输时间的较小消息,使用二叉树和二叉树以最小化集体的延迟。较大的消息通常被分成许多段,然后使用管道将这些段从根秩传递到所有其他段。即使在树分布情况下,消息仍然可以被分段。

问题在于,实际上每个集合操作都是使用具有相同标签的消息来实现的,通常带有负标签值(应用程序程序员不允许使用这些值)。这意味着MPI_Bcast在您的情况下,两个调用都将使用相同的标签来传输它们的消息,并且由于等级相同且通信器相同,因此消息将全部混淆。因此,仅在单独的通信器上进行并发集合的要求。

您的程序崩溃有两个原因。原因一是 MPI 库不提供MPI_THREAD_MULTIPLE. 第二个原因是如果消息被分成两个大小不均的块,例如较大的第一部分和较小的第二部分。两个集体调用之间的干扰可能导致第二个线程在等待第二个较小的块时接收指向第一个线程的大的第一个块。结果将是消息截断,并且将调用中止 MPI 错误处理程序。这通常不会导致段错误和核心转储,所以我认为您的 MPICH2 根本没有编译为线程安全的。

这不是 MPICH2 特定的。Open MPI 和其他实现也容易受到同样的限制。

于 2013-07-14T09:47:09.827 回答