如何在消息传递系统中实现屏障?

我的理解是,一个主进程向所有其他进程发送消息。 返回的所有其他进程都会向主进程发送消息。 这是否足以让障碍工作? 如果没有,那还需要什么呢?

我们来看看OpenMPI的屏障实现 。 虽然其他实现可能略有不同,但一般通信模式应该相同。

首先要注意的是MPI的屏障没有设置成本:到达MPI_Barrier调用的进程将阻塞,直到该组的所有其他成员也调用MPI_Barrier 。 请注意,MPI不要求它们到达同一个呼叫,只需要调用MPI_Barrier 。 因此,由于每个进程已经知道该组中的节点总数,因此不需要分发额外的状态来初始化该呼叫。

现在,让我们看一些代码:

 /* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2012 Oak Ridge National Labs. All rights reserved. * [...] */ [...] /* * barrier_intra_lin * * Function: - barrier using O(N) algorithm * Accepts: - same as MPI_Barrier() * Returns: - MPI_SUCCESS or error code */ int mca_coll_basic_barrier_intra_lin(struct ompi_communicator_t *comm, mca_coll_base_module_t *module) { int i; int err; int size = ompi_comm_size(comm); int rank = ompi_comm_rank(comm); 

首先,所有节点(除了排名为0的节点,根节点)发送一个通知,表明它们已到达根节点的屏障:

  /* All non-root send & receive zero-length message. */ if (rank > 0) { err = MCA_PML_CALL(send (NULL, 0, MPI_BYTE, 0, MCA_COLL_BASE_TAG_BARRIER, MCA_PML_BASE_SEND_STANDARD, comm)); if (MPI_SUCCESS != err) { return err; } 

之后,他们阻止等待来自root的通知:

  err = MCA_PML_CALL(recv (NULL, 0, MPI_BYTE, 0, MCA_COLL_BASE_TAG_BARRIER, comm, MPI_STATUS_IGNORE)); if (MPI_SUCCESS != err) { return err; } } 

根节点实现通信的另一端。 首先它阻塞直到它收到n-1通知(一个来自组中的每个节点,除了他自己,因为他已经在屏障呼叫中):

 else { for (i = 1; i < size; ++i) { err = MCA_PML_CALL(recv(NULL, 0, MPI_BYTE, MPI_ANY_SOURCE, MCA_COLL_BASE_TAG_BARRIER, comm, MPI_STATUS_IGNORE)); if (MPI_SUCCESS != err) { return err; } } 

一旦所有通知都到达,它就会发出每个节点正在等待的消息,表明每个人都已经到达屏障,之后它会自动离开屏障:

  for (i = 1; i < size; ++i) { err = MCA_PML_CALL(send (NULL, 0, MPI_BYTE, i, MCA_COLL_BASE_TAG_BARRIER, MCA_PML_BASE_SEND_STANDARD, comm)); if (MPI_SUCCESS != err) { return err; } } } /* All done */ return MPI_SUCCESS; } 

因此,通信模式首先是从所有节点到根节点的n:1 ,然后是从根节点到所有节点的1:n 。 为了避免带有请求的根节点过载,OpenMPI允许使用基于树的通信模式,但基本思路是相同的:所有节点在进入屏障时通知根,而根聚合结果并在通知后通知每个人准备继续。

不,这还不够。 一旦主进程向所有其他进程发送消息通知它已到达障碍,并且所有其他进程已响应以说它们也已到达障碍,则只有主进程知道所有进程已到达障碍。 在这种情况下,需要从主服务器到其他进程的另一条消息。

我没有对任何库中MPI障碍的实际实现提出任何要求,特别是我并不是说在实践中使用了所概述的消息序列,只是它在理论上有缺陷。