📄 mpi56.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<TITLE> ICPSEP Content
</TITLE>
<META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
</HEAD>
<BODY BGCOLOR="#F0F8FF">
<TABLE WIDTH="100%" >
<TR>
<TD align=left><FONT SIZE=+2>5.6 组间通信子</FONT> </TD>
<TD align=right><A HREF="mpi55.htm" tppabs="http://arch.cs.pku.edu.cn/parallelprogramming/mpispec/mpi55.htm"><IMG SRC="backward.gif" tppabs="http://arch.cs.pku.edu.cn/image/backward.gif" ALT="BACKWARD" HEIGHT=32 WIDTH=32></A>
<A HREF="mpi57.htm" tppabs="http://arch.cs.pku.edu.cn/parallelprogramming/mpispec/mpi57.htm"><IMG SRC="forward.gif" tppabs="http://arch.cs.pku.edu.cn/image/forward.gif" ALT="FORWARD" HEIGHT=32 WIDTH=32></A></TD>
</TR>
</TABLE>
<P>
<HR WIDTH="100%"></P>
<P>本节介绍了组间通信子的概念以及MPI中支持这一概念的部分.它描述了对于书写包含用户级服务器程序的支持.
</P>
<P>迄今所描述的所有点对点通信都涉及同一组内进程间的通信.如我们在本章前面所注意到的一样,
这种类型的通信叫"组内通信"并且所用的通信子叫"组内通信子".</P>
<P>在模块化或多学科的应用中,不同的进程组执行不同的模块而且不同模块内的进程在流水线内或更一般的模块图中相互间进行通信.
在这些应用中, 为一个进程指定目标进程的最自然的方式是利用目标组内的目标进程。在包含内部用户级服务器的应用中,每个服务器可以是为一个或更多客户机提供服务的进程组,同时客户机可以是使用一个或更多服务器服务的进程组.
在这些应用中,通过目标组内的序列号指定目标进程仍是最自然的.如前所述,这种类型的通信叫作"组间通信",所使用的通信子叫"组间通信子".</P>
<P>一个组间通信是不同组内进程间的点对点通信. 包含初始化组间通信操作进程的组叫"本地组",即接收者在接收里而发送者在发送里.包含目标进程的组叫"远程组",即接收者在发送里而发送者在接收里.
正如在组内通信中一样, 通过使用(communicator,rank)对来指定目标进程. 不象组内通信,序列号是与远程组相关的.</P>
<P>所有的组间通信子构造子都是阻塞的,并且要求本地和远程组间互不相连以便避免死锁.
</P>
<P>这里是组间通信和组间通信子的特性摘要: </P>
<UL>
<LI>组间和组内通信的点对点通信的语法是相同的.同一个通信子既可用于发送也可用于接收操作.
</LI>
<LI>无论是发送还是接收,目标进程都通过远程组内的序列号来访问. </LI>
<LI>使用组间通信子的通信保证不与任何使用不同通信子的通信相冲突. </LI>
<LI>组间通信子不能用于集合通信.</LI>
<LI>一个通信子或者提供组内通信或者提供组间通信.</LI>
</UL>
<P>函数MPI_COMM_TEST_INTER可被用于检测一个通信子是组间还是组内通信子.组间通信子可被用作一些其它通信子访问函数的参数.组间通信子不能用作一些组内通信子构造函数(例如
MPI_COMM_CREATE)的输入. </P>
<P>对实现者的建议:为实现点对点通信,在每个进程中可用一个多元组来描述通信子,包
括:</P>
<UL>
<P>group</P>
<P>send_context</P>
<P>receive_context</P>
<P>source.</P>
</UL>
<P>对于组间通信子,group描述了远程组, 而source则是本地组中进程的序列号.对于组内通信子,group是通信子组(远程等于本地),
source是此组内的进程序列号, send_context和receive_context是相同的. 一个组可用序列号--绝对地址转换表来描述.
</P>
<P>不同时考虑本地和远程组内的进程就不能合理地讨论组间通信子.想象组p内的进程P,该进程拥有通信子Cp,和组q内的进程Q,该进程拥有通信子Cq.则:</P>
<UL>
<LI>Cp.group描述了组Q,而Cq.group描述了组P.</LI>
<LI>Cp.send_context=Cq.receive_context而且此上下文在Q中是唯一的;</LI>
<LI>Cp.receive_context=Cq.send_context而且此上下文在P中是唯一的.</LI>
<LI>Cp.source是p中P的序列号而Cq是q中Q的序列号.</LI>
</UL>
<P>假定P使用组间通信子向Q发送一个消息.则P使用group表来找到Q的绝对地址;sourec和send_context被追加到此消息上.
</P>
<P>假定Q用一个使用组间通信子的显式的源参数获得了一个接收.则Q将receive_context匹配到消息上下文上而将源参数匹配到消息源上.
</P>
<P>同样的算法对于组内通信子也是适宜的. </P>
<P>为支持组间通信子访问子和构造子,有必要用附加的结构来补充这个模型,此模型应能够存储本地通信组的信息,并拥有附加的安全上下文.(对实现者的建议结束)</P>
<P><A NAME="5.6.1"></A><FONT SIZE=+1>5.6.1 组间通信子访问子</FONT></P>
<P>MPI_COMM_TEST_INTER(comm,flag) </P>
<UL>
<P>输入: comm 通信子(句柄)</P>
<P>输出: flag (逻辑值) </P>
</UL>
<P>int MPI_Comm_test_inter(MPI_Comm comm,int *flag)</P>
<P>MPI_COMM_TEST_INTER(COMM,FLAG,IERROR)</P>
<UL>
<P>INTEGER COMM,IERROR LOGICAL FLAG </P>
</UL>
<P>这个本地函数允许调用进程确定一个通信子是组间通信子还是组内通信子.如果是组间通信子则返回true,否则返回false.</P>
<P>在组内通信下,当一个组间通信子被用作上面所描述的通信子访问子的输入参数时,下表描述了动作.
</P>
<CENTER><TABLE BORDER=1 >
<TR>
<TD> MPI_COMM_*函数动作 <BR>
(在组间通信模式下)
<P> MPI_COMM_SIZE 返回本地组的大小<BR>
MPI_COMM_GROUP 返回本地组<BR>
MPI_COMM_RANK 返回本地组中的序列号</P>
</TD>
</TR>
</TABLE></CENTER>
<P>进一步讲,MPI_COMM_COMPARE对于组间通信是有效的.两个通信子必须或者是组内或者是组间通信子,
否则返回MPI_UNEQUAL.两个对应的本地和远程组必须正确比较以得到结果MPI_CONGRUENT和
MPI_SIMILAR.特别是,很可能得到结果MPI_SIMILAR,这是因为本地或远程组是近似但不同的.
</P>
<P>下面的访问子提供了对组间通信子远程组的一致性访问: </P>
<P>下面的都是本地操作. </P>
<P>MPI_COMM_REMOTE_SIZE(comm,size)</P>
<UL>
<P>输入: comm 组间通信子(句柄) </P>
<P>输出: size comm的远程组中的进程数(整数) </P>
</UL>
<P>int MPI_COMM_Comm_remote_size(MPI_Comm comm,int *size) </P>
<P>MPI_COMM_REMOTE_SIZE(COMM,SIZE,IERROR) </P>
<UL>
<P>INTEGER COMM,SIZE,IERROR</P>
</UL>
<P>MPI_COMM_REMOTE_GROUP(comm,group) </P>
<UL>
<P>输入: comm 组间通信子(句柄) </P>
<P>输出: group 对应于comm的远程组(句柄) </P>
</UL>
<P>int MPI_Comm_remote_group(MPI_Comm comm,MPI_Group *group) </P>
<P>MPI_COMM_REMOTE_GROUP(COMM,GROUP,IERROR)</P>
<UL>
<P>INTEGER COMM,GROUP,IERROR </P>
</UL>
<P>基本原理:对于组间通信子的本地和远程组的对称访问是重要的,因此,象MPI_COMM_REMOTE_SIZE一样提供了这个函数.(基本原理结束)</P>
<P><A NAME="5.6.2"></A><FONT SIZE=+1>5.6.2 组间通信子操作 </FONT></P>
<P>本节介绍了四个阻塞的组间通信子操作.MPI_INTERCOMM_CREATE用于将两个组内通信子绑定到
一个组间通信子上;函数MPI_INTERCOMM_MERGE通过合并组间通信子的本地和远程组创建一个
组内通信子.函数MPI_COMM_DUP和MPI_COMM_FREE,如前所述,分别复制和释放一个组间通信子.</P>
<P>禁止绑定到一个组间通信子上的本地和远程组发生重迭.如果有重迭则程序出错并可能发生死锁.(若一个进程是多线索的,且MPI调用仅阻塞一个线索,而非一个进程,则可支持"双重成员
".由用户负责确保代表一个进程两个角色的调用被两个独立的线索所执行.)
</P>
<P>函数MPI_INTERCOMM_CREATE可在下列条件下被用来从两个已存在的组内通信子中创建一个
组间通信子:每一组中至少有一个可选成员("组首领")有能力与其它组的被选成员通信;即存在一个两个首领都属于它的"平等"通信子,且每个首领都知道在此平等通信子中其它首领的序列号
(两个首领可以是同一进程).而且,每个组的成员知道它们首领的序列号。</P>
<P>从两个组内通信子中构造一个组间通信子需要在本地组和远程组中进行分离的集合操作,就象本地组的进程和远程组的进程间的点对点通信一样.
</P>
<P>在标准的MPI实现中(在初始化时使用静态进程分配),通信子MPI_COMM_WORLD(或其复制品)
可作为此平等通信子. 在动态MPI实现中,在这里,例如,一个进程可在MPI执行过程中派生新的子进程,父进程可作为旧通信空间与包含父子进程的新通信世界间的桥梁.</P>
<P><A HREF="mpi61.htm" tppabs="http://arch.cs.pku.edu.cn/parallelprogramming/mpispec/mpi61.htm">第六章</A>所描述的应用拓扑函数不适合于组间通信子.
要求此能力的用户应该利用 MPI_INTERCOMM_MERGE来建立一个组内通信子,然后将图与笛卡尔拓扑能力应用到组内通信子上,创建一个适当的拓扑定位的组内通信子.对于这种情况,在不丢失一般性的前提下也可设计一个自己的应用拓扑机制.
</P>
<P>MPI_INTERCOMM_CREATE(local_comm,local_leader,peer_comm,remote_leader
,tag,ne wintercomm) </P>
<UL>
<P>输入: local_comm 本地组内通信子(句柄)</P>
<P> local_leader local_comm内的本地组首领的序列号(整数) </P>
<P> peer_comm "平等"组内通信子;仅在local_leader中有意义(句柄)</P>
<P> remote_leader peer_comm中远程组首领的序列号;仅在local_leader中有意义(句柄)
</P>
<P> tag "安全"标志(整数) </P>
<P>输出: newintercomm 新的组间通信子(句柄)</P>
</UL>
<P>int MPI_Intercomm_create(MPI_Comm local_comm,int local_leader,MPI_Comm
peer_comm,int remote_leader,int tag,MPI_Comm *newintercomm) </P>
<P>MPI_INTERCOMM_CREATE(LOCAL_COMM,LOCAL_LEADER,PEER_COMM,REMOTE_LEADER
,TAG,N EWINTERCOMM,IERROR) </P>
<UL>
<P>INTEGER LOCAL_COMM,LOCAL_LEADER,PEER_COMM,REMOTE_LEADER,TAG ,NEWINTERCOMM,IERROR
</P>
</UL>
<P>本调用创建了一个组间通信子.它对于本地和远程组的合并是集合性的.进程应该在每个组中提供相同的local_comm和local_leader参数.对于remote_leader,local_leader和tag不允许通配符.</P>
<P>本调用通过通信子peer_comm和首领间的标志tag来使用点对点通信.这样,就必须关心在
peer_comm上是否有可能干扰这个通信的挂起通信.</P>
<P>对用户的建议: 我们推荐使用现成的平等通信子,例如MPI_COMM_WORLD的复制品,以避免与平等通信子发生干扰.(对用户的建议结束)
</P>
<P>MPI_INTERCOMM_MERGE(intercomm,high,newintracomm) </P>
<UL>
<P>输入: intercomm 组间通信子(句柄) </P>
<P> high (逻辑值) </P>
<P>输出: newintracomm 新的组内通信子(句柄) </P>
</UL>
<P>int MPI_Intercomm_merge(MPI_Comm intercomm,int high,MPI_Comm *newintracomm)
</P>
<P>MPI_INTERCOMM_MERGE(INTERCOMM,HIGH,INTRACOMM,IERROR)</P>
<UL>
<P>INTEGER INTERCOMM,INTRACOMM,IERROR LOGICAL HIGH</P>
</UL>
<P>此函数从两个与intercomm相关的组的并中创建了一个组内通信子.对于两个组中每一个,其中的所有进程都应提供相同的high值.如果一个组中的进程提供值high=false,而另一个组中的进程提供值high=true,则并将"低"组排在"高"组的前面.如果所有的进程提供相同的high参数,
则并的顺序是任意的.此调用在两个组的并中是阻塞和集合性.</P>
<P>对实现者的建议:MPI_INTERCOMM_MERGE,MPI_COMM_FREE和MPI_COMM_DUP的实现类似于
MPI_INTERCOMM_CREATE的实现,所不同的是:用于组首领间通信的上下文是输入组间通信子所私有的上下文而非桥梁通信子内部的上下文.
</P>
<P><A NAME="5.6.3"></A><FONT SIZE=+1>5.6.3 组间通信例子</FONT></P>
<P>例1:三组"流水线" </P>
<P>组0与组1通信.组1与组2通信.因此,组0需要一个组间通信子,组1需要两个组间通信子,而组2需要一个组间通信子.</P>
<P> main(int argc,char**argv)<BR>
{<BR>
MPI_Comm myComm;/*本地子组的组内通信子*/ <BR>
MPI_Comm myFirstComm;/*组间通信子*/ <BR>
MPI_Comm mySecondComm;/*第二个组间通信子(仅用于组1)*/ <BR>
int membershipKey;<BR>
int rank;</P>
<P> MPI_Init(&argc,&argv);<BR>
MPI_Comm_rank(MPI_COMM_WORLD,&rank);</P>
<P> /*用户代码必须在范围[0,1,2]中产生membershipKey*/ <BR>
membershipKey=rank%3; </P>
<P> /*为本地子组建立组内通信子*/ <BR>
MPI_Comm_split(MPI_COMM_WORLD,membershipKey,rank,&myComm); </P>
<P> /*建立组间通信子,标志是硬编码*/ <BR>
if(membershipKey==0) <BR>
{<BR>
/*组0与组1通信*/ <BR>
MPI_Intercomm_create(myComm,0,MPI_COMM_WORLD,1, 1,&myFirstComm);
<BR>
}<BR>
else if (membershipKey==1) <BR>
{<BR>
/*组1与组0和2通信*/<BR>
MPI_Intercomm_create(myComm,0,MPI_COMM_WORLD,0, 1,&myFirstComm);<BR>
MPI_Intercomm_ereate(myComm,0,MPI_COMM_WORLD,2, 12,&mySecondComm);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -