📄 mpi56.htm
字号:
<BR>
}<BR>
else if (membershipKey==2) <BR>
{<BR>
/*组2与组1通信*/ <BR>
MPI_Intercomm_create(myComm,0,MPI_COMM_WORLD,1, 12,&myFirstComm);
<BR>
}</P>
<P> /*做工作...*/</P>
<P> switch(membershipKey)/*释放适宜的通信子*/ <BR>
{<BR>
case 1: <BR>
MPI_COMM_free(&mySecondComm); <BR>
case 0: <BR>
case 2: <BR>
MPI_COMM_free(&myFirstComm); <BR>
break; <BR>
}</P>
<P> MPI_Finalize(); <BR>
}</P>
<P>例2:三组"环" </P>
<P>组0与组1通信.组1与组2通信.组0与组2通信.因此,每组需要两个通信子. </P>
<P> main(int argc,char **argv)<BR>
{<BR>
MPI_Comm myComm;/*本地子组的组内通信子*/ <BR>
MPI_Comm myFirstComm;/*组间通信子*/ <BR>
MPI_Comm mySecondComm; <BR>
MPI_Status status;<BR>
int membershipKey; <BR>
int rank;</P>
<P> MPI_Init(&argc,&argv);<BR>
MPI_Comm_rank(MPI_COMM_WORLD,&rank); <BR>
...</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和2通信*/ <BR>
MPI_Intercomm_create(myComm, 0,MPI_COMM_WORLD,1, 1,&myFirstComm);
<BR>
MPI_Intercomm_create(myComm, 0,MPI_COMM_WORLD,2, 2,&mySecondComm);
<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_create(myComm,0, MPI_COMM_WORLD, 2, 12,&mySecondComm);<BR>
}<BR>
else if (membershipKey==2) <BR>
{<BR>
/*组2与组0和1通信*/<BR>
MPI_Intercomm_create(myComm, 0,MPI_COMM_WORLD,0, 2,&myFirstComm);
<BR>
MPI_Intercomm_create(myComm,0,MPI_COMM_WORLD,1, 12,&mySecondComm);
<BR>
}</P>
<P> /*做一些工作*/</P>
<P> /*然后在中止前释放通信子*/ <BR>
MPI_Comm_free(&myFirstComm); <BR>
MPI_Comm_free(&mySecondComm);<BR>
MPI_Comm_free(&myComm); <BR>
MPI_Finalize();<BR>
}</P>
<P>例3:为组间通信建立名字服务 </P>
<P>后面的过程举例说明了能够创建名字服务的进程,名字服务通过一个包含服务器通信子的集合和一个由两个组共同选定的标志名来建立组间通信子.</P>
<P>当所有MPI进程执行了MPI_INIT后,每个进程调用下面所定义的函数例子Init_serve().接着,
如果new_world返回NULL,得到NULL的进程则需要在一个重新激活的循环Do_serve()内实现一个服务器函数.
其它的每个进程通过使用new_world作为新的有效的"全局"通信子来作它们预先规划好的计算。当不再需要服务器时,某一个指定的进程调用Undo_Server()来清除服务器.
</P>
<P>此方法包括以下特征: </P>
<UL>
<LI>为多重名字服务提供支持</LI>
<LI>将名字服务限制在指定进程的能力 </LI>
<LI>任意使用和退出此服务器的能力 </LI>
</UL>
<P> #define INIT_SERVER_TAG_1 666 <BR>
#define UNDO_SERVER_TAG_1 777</P>
<P> static int server_key_val;</P>
<P> /*对于server_comm的属性管理,复制回调*/ <BR>
void handle_copy_fn(MPI_Comm *oldcomm,int *keyval, void *extra_state,
void *attribute_val_in,void **attribute_val_out,int *flag)<BR>
{<BR>
/*复制句柄*/<BR>
*attributez_val_out=attribute_val_in;<BR>
*flag=1;/*指出此拷贝将要发生*/ <BR>
}</P>
<P> int Init_server(peer_comm,rank_of_server,server_comm,new_world)<BR>
MPI_Comm peer_comm;<BR>
int rank_of_server;<BR>
MPI_Comm *server_comm; <BR>
MPI_Comm *new_world;/*新的有效的通信子,无服务器*/ <BR>
{<BR>
MPI_Comm temp_comm, lone_xomm; <BR>
MPI_Group peer_group, temp_group;<BR>
int rank_in_peer_comm,size,color,key=0; <BR>
int peer_leader,peer_leader_rank_in_temp_comm;</P>
<P> MPI_Comm_rank(peer_comm,&rank_in_peer_comm);<BR>
MPI_Comm_size(peer_comm,*size); </P>
<P> if((size<2) ||(0>rank_of_server)||(rank_of_server >= siae))
<BR>
return (MPI_ERR_OTHER); <BR>
/*通过将peer_comm分成服务器进程和其它进程,来创建两个通信子*/ </P>
<P> peer_leader=(rank_of_server+1)%size;/*任意选择*/ </P>
<P> if((color=(rank_in_peer_comm==rank_of_server)))<BR>
{<BR>
MPI_Comm_split(peer_comm,color,key,&lone_comm); </P>
<P> MPI_Intercomm_create(lone_comm,0,peer_comm,peer_leader, INIT_SERVER_TAG_1,server_comm);
</P>
<P> MPI_Comm_free(&lone_comm);<BR>
*new_world=(MPI_Comm)0;<BR>
}<BR>
else<BR>
{<BR>
MPI_Comm_Split(peer_comm,color,key,&temp_comm); </P>
<P> MPI_Comm_group(peer_comm,&peer_group); <BR>
MPI_Comm_group(temp_comm,&temp_group); <BR>
MPI_Group_translate_ranks(peer_group, 1, &peer_leader,temp_group,&peer_leader_rank_in_temp_comm);
</P>
<P> MPI_Intercomm_create(cemp_comm,peer_leader_rank_in_temp_comm, peer_comm,rank_of_server,
INIT_SERVER_TAG_1,server_comm); <BR>
/*将new_world通信属性附到server_comm上*/ </P>
<P> /*多线索的关键部分*/ <BR>
if(server_keyval==MPI_KEYVAL_INVALID) <BR>
{<BR>
/*为服务器keyval获得进程本地名字*/ <BR>
MPI_Attr_keyval_create(handle_copy_fn,NULL, &Server_keyval,NULL);<BR>
}</P>
<P> *new_world=temp_comm;</P>
<P> /*在组间通信子上的组内通信子缓冲句柄*/ <BR>
MPI_Attr_put(server_comm,server_keyval,(void *)(*new_world)); <BR>
}</P>
<P> return(MPI_SUCCESS); <BR>
}</P>
<P>实际的服务器进程将交付运行下列代码: </P>
<P> int Do_server(server_comm) <BR>
MPI_Comm server_comm; <BR>
{<BR>
void init_queue(); <BR>
int en_queue(),de_queue();/*为后面的匹配保存整数三元组(不显示fns)*/
</P>
<P> MPI_Comm comm; <BR>
MPI_Status status; <BR>
int client_tag,client_source; <BR>
int client_rank_in_new_world,pairs_rank_in_new_world; <BR>
int buffer[10],count=1;</P>
<P> void *queue;<BR>
init_queue(&queue); </P>
<P> for(;;)<BR>
{<BR>
MPI_Recv(buffer,count,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG, server_comm,&status);<BR>
/*从任意客户机中接收*/ </P>
<P> /*确定客户机*/ <BR>
client_tag=status.MPI_TAG;<BR>
client_source=status.MPI_SOURCE; <BR>
client_rank_in_new_world=buffer[0]; </P>
<P> if(client_tag==UNDO_SERVER_TAG_1)/*中止进程的客户机*/ <BR>
{<BR>
while (de_queue,MPI_ANY_TAG,&pairs_rank_in_new_world, &pairs_rank_in_server))
<BR>
;<BR>
MPI_Intercomm_free(&server_comm);<BR>
break;<BR>
}</P>
<P> if(de_queue(queue,client_tag,&pairs_rank_in_new_world, &pairs_rank_in_server))<BR>
{<BR>
/*用一些标志进行成对匹配,告诉它们相互的情况*/ <BR>
buffer[0]=pairs_rank_in_new_world;<BR>
MPI_Send(buffer,1,MPI_INT,client_src,client_tag, server_comm);
<BR>
buffer[0]=client_rank_in_new_world; <BR>
MPI_Send(buffer,1,MPI_INT,pairs_rank_in_server,client_tag, server_comm);
<BR>
}<BR>
else <BR>
en_queue(queue,client_tag,client_source, client_rank_in_new_world);</P>
<P> }</P>
<P> }</P>
<P>当服务器不再需要时由一个专门的进程来负责结束它.调用Undo_server将中止服务器函数.
</P>
<P> int Undo_server(server_comm)/*结束服务器的客户机例程*/ <BR>
MPI_Comm *server_comm;<BR>
{<BR>
int buffer = 0;<BR>
MPI_Send(&buffer,1, MPI_INT,0, UNDO_SERBER_TAG_1,*server_comm);
<BR>
MPI_Intercomm_free(server_comm); <BR>
}</P>
<P>下面是一个用于组间通信的阻塞的名字服务,其语义约束与MPI_Intercomm_create相同,但是简化了语法.它仅使用了创建名字服务的功能.
</P>
<P> int Intercomm_name_create(local_comm,server_comm,tag,comm) <BR>
MPI_Comm local_comm, server_comm;<BR>
int tag;<BR>
MPI_Comm *comm; <BR>
{<BR>
int error;<BR>
int found;/*attribute acquisitio mgmt for new_world */<BR>
/*server_comm中的comm*/ </P>
<P> void *val; </P>
<P> MPI_Comm new_world; </P>
<P> int brffer[10],rank; <BR>
int local_leader=0;</P>
<P> MPI_Attr_get(server_comm,server_keyval,&val,&found); <BR>
new_world=(MPI_Comm)val;/*收回缓冲句柄*/</P>
<P> MPI_Comm_rank(server_comm,&rank);/*本地组中的序列号*/</P>
<P> if(rank==local_leader) <BR>
{<BR>
buffer[0]=rank;<BR>
MPI_Send(&buffer,1,MPI_INT,0,tag,server_comm); <BR>
MPI_Recv(&buffer,1,MPI_INT,0,tag,server_comm); <BR>
}</P>
<P> error =MPI_Intercomm_create(local_leader,local_comm,buffer[0],
new_world,tag,comm); </P>
<P> return(error);</P>
<P> }</P>
<P>
<HR WIDTH="100%"></P>
<TABLE WIDTH="100%" >
<TR>
<TD align=left>Copyright: NPACT </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>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -