📄 mpi55.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.5 针对性例子</FONT></TD>
<TD align=right><A HREF="mpi54.htm" tppabs="http://arch.cs.pku.edu.cn/parallelprogramming/mpispec/mpi54.htm"><IMG SRC="backward.gif" tppabs="http://arch.cs.pku.edu.cn/image/backward.gif" ALT="BACKWARD" HEIGHT=32 WIDTH=32></A>
<A HREF="mpi56.htm" tppabs="http://arch.cs.pku.edu.cn/parallelprogramming/mpispec/mpi56.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><A NAME="5.5.1"></A><FONT SIZE=+1>5.5.1当前练习#1</FONT></P>
<P>例#1a: </P>
<P> main(int argc,char **argv)<BR>
{<BR>
int me,size;<BR>
... <BR>
MPI_Init(&argc,&argv); <BR>
MPI_Comm_rank(MPI_COMM_WORLD,&me); <BR>
MPI_Comm_size(MPI_COMM_WORLD,&size); </P>
<P> (void)printf("Process %d size %d",me,size); <BR>
... <BR>
MPI_Finalize();<BR>
}</P>
<P>例#1a是一个对自身进行合法初始化但不做任何事的程序,程序中引用了"all"
通信 子并打印了一个消息。其自身也能合法终止。该例不意味着MPI本身支持类printf通信。
</P>
<P>例#1b(假设size是偶数) </P>
<P> main(int argc,char **argv) <BR>
{<BR>
int me,size; <BR>
int SOME_TAG=0; <BR>
... <BR>
MPI_Init(&argc,&argv); </P>
<P> MPI_Comm_rank(MPI_COMM_WORLD,&me);/*本地*/ <BR>
MPI_Comm_size(MPI_COMM_WORLD,&size);/*本地*/ </P>
<P> if ((me%2)==0)<BR>
{<BR>
/*如果不是最高编号的进程则发送*/ <BR>
if((me+1)<size)<BR>
MPI_Send(...,me+1,SOME_TAG,MPI_COMM_WORLD);<BR>
}<BR>
else <BR>
MPI_Recv(...,me-1,SOME_TAG,MPI_COMM_WORLD);</P>
<P> ...<BR>
MPI_Finalize(); <BR>
}</P>
<P>例#1b有计划地阐述了"all"通信子中奇偶进程间的消息交换.</P>
<P><A NAME="5.5.2"></A><FONT SIZE=+1>5.5.2 当前练习#2 </FONT></P>
<P> main(int argc,char **argv)<BR>
{<BR>
int me,count; <BR>
void *data;<BR>
... </P>
<P> MPI_Init(&argc,&argv);<BR>
MPI_Comm_rank(MPI_COMM_WORLD,&me);</P>
<P> if(me==0) <BR>
{<BR>
/*得到输入,建立缓冲区"data"*/ <BR>
...<BR>
}</P>
<P> MPI_Bcast(data,count,MPI_BYTE,0,MPI_COMM_WORLD);</P>
<P> ...</P>
<P> MPI_Finalize(); <BR>
}</P>
<P>本例阐述了集合通信的使用.</P>
<P><A NAME="5.5.3"></A><FONT SIZE=+1>5.5.3(近似)当前练习#3</FONT></P>
<P> main(int argc,char **argv)<BR>
{<BR>
int me,count,count2; <BR>
void *send_buf,*recv_buf,*send_buf2,*recv_buf2; <BR>
MPI_Group MPI_GROUP_WORLD,grprem; <BR>
MPI_Comm commslave; <BR>
static int rank[]={0};<BR>
...<BR>
MPI_Init(&argc,&argv);<BR>
MPI_Comm_group(MPI_COMM_WORLD,&MPI_GROUP_WORLD); <BR>
MPI_Comm_rank(MPI_COMM_WORLD,&me);/*本地/</P>
<P> MPI_Group_excl(MPI_GROUP_WORLD,1,ranks,&grprem);/*本地*/ MPI_Comm_create(MPI_COMM_WORLD,grprem,&commslave);</P>
<P> if((me!=0)<BR>
{<BR>
/*在从机上计算*/ <BR>
...<BR>
MPI_Reduce(send_buf,recv_buff,count,MPI_INT,MPI_SUM,1,commslave);<BR>
...<BR>
}<BR>
/*0则立即作此归约操作,其它则稍后再做*/ <BR>
MPI_Reduce(send_buf2,recv_buff2,count2, MPI_INT,MPI_SUM,0,MPI_COMM_WORLD);</P>
<P> MPI_Comm_free(&commslave); <BR>
MPI_Group_free(&MPI_GROUP_WORLD); <BR>
MPI_Group_free(&grprem); <BR>
MPI_Finalize(); <BR>
}</P>
<P>本例阐述了如何创建一个组,该组包含了除"all"组中第0个进程之外的所有进程,同时阐述了如何为该新组(commslave)形成一个通信子。此新通信子在一个集合调用中被使用,而且所有进程在上下文MPI_COMM_WORLD中都执行一个集合调用。本例还阐述了两个通信子(本质上具有不同的上下文)如何保护通信。亦即,MPI_COMM_WORLD中的通信与commslave中的通信隔离开,反之亦然。</P>
<P>概要地讲,“组安全性”是通过通信子获得的,这是因为在任何进程上通信子内的不同上下文被强制为唯一的。</P>
<P><A NAME="5.5.4"></A><FONT SIZE=+1>5.5.4 例#4 </FONT></P>
<P>下面的例子目的是阐述点对点与集合通信之间的安全性。MPI保证了单独一个通信子能够安全地进行点对点与集合通信。</P>
<P> #define TAG_ARBITRARY 12345<BR>
#define SOME_COUNT 50</P>
<P> main(int argc,char **argv)<BR>
{<BR>
int me;<BR>
MPI_Request request[2];<BR>
MPI_Status status[2];<BR>
MPI_Group MPI_GROUP_WORLD,subgroup; <BR>
int ranks[]={2,4,6,8};<BR>
MPI_Comm the_comm;<BR>
... <BR>
MPI_Init(&argc,&argv);<BR>
MPI_Comm_group(MPI_COMM_WORLD,&MPI_GROUP_WORLD); </P>
<P> MPI_Group_incl(MPI_GROUP_WORLD,4,ranks,&subgroup);/*本地*/<BR>
MPI_Group_rank(subgroup,&me);/*本地*/ </P>
<P> MPI_Comm_create(MPI_COMM_WORLD,subgroup,&the_comm);</P>
<P> if (me!=UNDEFINED)<BR>
{<BR>
MPI_Irecv(buff1,count,MPI_DOUBLE,MPI_ANY_SOURCE,TAG_ARBITRARY,the_comm,
request); MPI_Isend(buff2,count,MPI_DOUBLE,(me+1)%4,TAG_ARBITRARY,
the_comm,request+1);<BR>
}</P>
<P> for(i=0;i<SOME_COUNT;i++)<BR>
MPI_Reduce(...,the_comm);<BR>
MPI_Waitall(2,request,status);</P>
<P> MPI_Comm_free(&the_comm);<BR>
MPI_Group_free(&MPI_GROUP_WORLD);<BR>
MPI_Group_free(&subgroup);<BR>
MPI_Finalize();<BR>
}</P>
<P><A NAME="5.5.5"></A><FONT SIZE=+1>5.5.5 库例#1 </FONT></P>
<P>主程序:</P>
<P> main(int argc,char **argv)<BR>
{<BR>
int done=0; <BR>
user_lib_t *libh_a,*libh_b;<BR>
void *dataset1,*dataset2;<BR>
...<BR>
MPI_Init(&argc,&argv);<BR>
...<BR>
init_user_lib(MPI_COMM_WORLD,&libh_a); <BR>
init_user_lib(MPI_COMM_WORLD,&libh_b);<BR>
...<BR>
user_start_op(libh_a,dataset1);<BR>
user_start_op(libh_b,dataset2);<BR>
...<BR>
while(!done) <BR>
{<BR>
/*起作用*/ <BR>
...<BR>
MPI_Reduce(...,MPI_COMM_WORLD); <BR>
... <BR>
/*如果done,则见下面*/ <BR>
...<BR>
}<BR>
user_end_op(libh_a);<BR>
user_end_op(libh_b); </P>
<P> uninit_user_lib(libh_a); <BR>
uninit_user_lib(libh_b); <BR>
MPI_Finalize();<BR>
}</P>
<P>用户库初始化代码: <BR>
void init_user_lib(MPI_Comm *comm,user_lib_t **handle)<BR>
{<BR>
user_lib_t *save;</P>
<P> user_lib_initsave(&save);/*本地*/ <BR>
MPI_Comm_dup(comm,&(save->comm));</P>
<P> /*其它初始化*/ <BR>
...</P>
<P> *handle=save;<BR>
}</P>
<P>用户启动代码: <BR>
void user_start_op(user_lib_t *handle,void *data)<BR>
{<BR>
MPI_Irecv(...,handle->comm,&(handle->irecv_handle)); <BR>
MPI_Isend(...,handle->comm,&(handle->irecv_handle)); <BR>
}</P>
<P>用户通信清除代码:</P>
<P> void user_end_op(usr_lib_t *handle)<BR>
{<BR>
MPI_Status *status; <BR>
MPI_Wait(handle->isend_handle,status); <BR>
MPI_Wait(handle->irecv_handle,status); <BR>
}</P>
<P>用户对象清除代码: </P>
<P> void uninit_user_lib(user_lib_t *handle)<BR>
{<BR>
MPI_Comm_free(&(handle->comm));<BR>
free(handle);<BR>
}</P>
<P><A NAME="5.5.6"></A><FONT SIZE=+1>5.5.6 库例#2</FONT></P>
<P>主程序:<BR>
main(int argc **argv) <BR>
{<BR>
int ma, mb; <BR>
MPI_Group MPI_GROUP_WORLD,group_a, group_b; <BR>
MPI_Comm comm_a,commb; </P>
<P> static int list_a[] = {0,1};<BR>
#if defined(EXAMPLE_2B) |defined(EXAMPLE_2C)<BR>
static int list_b[] = {0, 2, 3}; </P>
<P>#else/* EXAMPLE_2A */ <BR>
static int list_b[] = {0, 2};<BR>
#endif<BR>
int size_list_a = sizeof(list_a)/sizeof(int); <BR>
int size_list_b = sizeof(list_b)/sizeof(int); </P>
<P> ...<BR>
MPI_Init(&argc, &argv);<BR>
MPI_Comm_group(MPI_COMM_WORLD, &MPI_GROUP_WORLD); </P>
<P> MPI_Group_incl(MPI_GROUP_WORLD,size_list_a,&group_a); <BR>
MPI_group_incl(MPI_GROUP_WORLD,size-list_b,&group_b); </P>
<P> MPI_Comm_create(MPI_COMM_WORLD,group_a, &comm_a); <BR>
MPI_Comm_create(MPI_COMM_WORLD,group_b, &comm_b); </P>
<P> MPI_Comm_rank(comm_a, &ma);<BR>
MPI_Comm_rant(comm_b, &mb); </P>
<P> if(ma != MPI_UNDEFINED) <BR>
lib_call(comm_a); </P>
<P> if(mb != MPI_UNDEFINED)<BR>
{<BR>
lib_call(comm_b); <BR>
lib_call(comm_b);<BR>
}</P>
<P> MPI_Comm_free(&comm_a); <BR>
MPI_Comm_free(&comm_b);<BR>
MPI_Group_free(&group_a);<BR>
MPI_Group_free(&group_b); <BR>
MPI_Group_free(&MPI_GROUP_WORLD);<BR>
MPI_Finalize(); <BR>
}</P>
<P>库:</P>
<P> void lib_call(MPI_Comm comm)<BR>
{<BR>
int me, done = 0;<BR>
MPI_Comm_rank(comm,&me);<BR>
if(me == 0)<BR>
while(!done)<BR>
{<BR>
MPI_Recv(..., MPI_ANY_SOURCE, MPI_ANY_TAG, comm);<BR>
...<BR>
}<BR>
else<BR>
{<BR>
/*起作用*/ <BR>
MPI_Send(...,0, ARBITRARY_TAG, comm);<BR>
...<BR>
}<BR>
#ifdef EXAMPLE_2C<BR>
/* 包含(resp, exclude)用于safety (resp, no safety): */ <BR>
MPI_Barrier(comm); <BR>
#endif<BR>
}</P>
<P>根据程序是否在lib_b中包含序列号等级3,以及是否在lib_call中进行同步,可将上面的例子实际
上当做三个例子.本例所阐述的是,不管上下文如何,使用同样上下文对lib_call进行的后续调用相互间无须是安全的(口语上,成为“后标志”).
如果加上MPI_Barrier, 就要考虑安全性.已经证明,即使使用上下文, 库也要仔细书写.当不包括序列号3时,就无须通过同步来从后标志中获取安全性.
</P>
<P>假如MPI提供基本的保证,则类似于"reduce"和"allreduce"这样的算法就会有足够强大的选
择特性来保证其固有的正确性(无后标志).对使用相同的根和不同的根的典型树广播算法的多重调用也是这样.
这里我们依赖于MPI的两个保证: 同一上下文内的进程间的成对顺序,及资源的可选择性--删除任一个特征就等于去掉了不要求后标志这一保证.
</P>
<P>试图作非确定性广播或包括通配符操作的其它调用一般不具备诸如 "reduce","allreduce",及"broadcast"这种确定性实现的好的特性.这种算法必须利用单调上升的标志(在一个通信子范围内)来保持正确性.
</P>
<P>前面的所有调用都假定是用点对点操作来实现集合调用.MPI实现既可用也可不用点对点操作来实现集合调用.这些算法用于阐述正确性和安全性问题,而不管MPI如何实现其集合调用.
见<A HREF="mpi58.htm" tppabs="http://arch.cs.pku.edu.cn/parallelprogramming/mpispec/mpi58.htm">5.8节</A>.</P>
<P>
<HR WIDTH="100%"></P>
<TABLE WIDTH="100%" >
<TR>
<TD align=left>Copyright: NPACT </TD>
<TD align=right><A HREF="mpi54.htm" tppabs="http://arch.cs.pku.edu.cn/parallelprogramming/mpispec/mpi54.htm"><IMG SRC="backward.gif" tppabs="http://arch.cs.pku.edu.cn/image/backward.gif" ALT="BACKWARD" HEIGHT=32 WIDTH=32></A>
<A HREF="mpi56.htm" tppabs="http://arch.cs.pku.edu.cn/parallelprogramming/mpispec/mpi56.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 + -