MPI基础

#include <stdio.h>
#include <string.h>
#include "mpi.h"
/*1. int MPI_Init (int* argc ,char** argv[] )
该函数通常应该是第一个被调用的MPI函数用于并行环境初始化,其后面的代码到 MPI_Finalize()函数之前的代码在每个进程中都会被执行一次。
–  除MPI_Initialized()外, 其余所有的MPI函数应该在其后被调用。
–  MPI系统将通过argc,argv得到命令行参数(也就是说main函数必须带参数,否则会出错)。

2. int MPI_Finalize (void)
–  退出MPI系统, 所有进程正常退出都必须调用。 表明并行代码的结束,结束除主进程外其它进程。
–  串行代码仍可在主进程(rank = 0)上运行, 但不能再有MPI函数(包括MPI_Init())。

3. int MPI_Comm_size (MPI_Comm comm ,int* size )
–  获得进程个数 size。
–  指定一个通信子,也指定了一组共享该空间的进程, 这些进程组成该通信子的group(组)。
–  获得通信子comm中规定的group包含的进程的数量。

4. int MPI_Comm_rank (MPI_Comm comm ,int* rank)
–  得到本进程在通信空间中的rank值,即在组中的逻辑编号(该 rank值为0到p-1间的整数,相当于进程的ID。)

5. int MPI_Send( void *buff, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
–void *buff:你要发送的变量。
–int count:你发送的消息的个数(注意:不是长度,例如你要发送一个int整数,这里就填写1,如要是发送“hello”字符串,这里就填写6(C语言中字符串未有一个结束符,需要多一位))。
–MPI_Datatype datatype:你要发送的数据类型,这里需要用MPI定义的数据类型,可在网上找到,在此不再罗列。
–int dest:目的地进程号,你要发送给哪个进程,就填写目的进程的进程号。
–int tag:消息标签,接收方需要有相同的消息标签才能接收该消息。
–MPI_Comm comm:通讯域。表示你要向哪个组发送消息。
6. int MPI_Recv( void *buff, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
–void *buff:你接收到的消息要保存到哪个变量里。
–int count:你接收消息的消息的个数(注意:不是长度,例如你要发送一个int整数,这里就填写1,如要是发送“hello”字符串,这里就填写6(C语言中字符串未有一个结束符,需要多一位))。它是接收数据长度的上界. 具体接收到的数据长度可通过调用MPI_Get_count 函数得到。
–MPI_Datatype datatype:你要接收的数据类型,这里需要用MPI定义的数据类型,可在网上找到,在此不再罗列。
–int dest:接收哪个进程号的信息,你要需要哪个进程接收消息就填写接收进程的进程号。
–int tag:消息标签,需要与发送方的tag值相同的消息标签才能接收该消息。
–MPI_Comm comm:通讯域。
–MPI_Status *status:消息状态。接收函数返回时,将在这个参数指示的变量中存放实际接收消息的状态信息,包括消息的源进程标识,消息标签,包含的数据项个数等。
*/
int main(int argc, char* argv[])
{
    int numprocs, myid, source;
    MPI_Status status;/*MPI_Status是MPI中定义的类型数据,分别有三个域,可以通过status.MPI_SOURCE,
    status.MPI_TAG和status.MPI_ERROR的方式调用这三个信息,其中status已经定义为MPI_Status变量。
    这三个信息分别返回的值是所收到数据发送源的进程号,该消息的tag值和接收操作的错误代码。
*/
    char message[100];
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);//MPI_COMM_WORLD指“MPI应用中的所有进程”,它称为通信子,并且提供消息传递所需的所有信息
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    if (myid != 0) {  //非0号进程发送消息
        strcpy_s(message, "Hello World!");//用strcpy_s比strcpy更安全!
        MPI_Send(message, strlen(message)+1, MPI_CHAR, 0, 99,//strlen不包含 \0 所以要加1
            MPI_COMM_WORLD);// 发送的消息,长度,消息类型,接收哪个源进程的信息,消息标签(相同才能接收),通信域
    }
    else {   // myid == 0,即0号进程接收消息
        for (source = 1; source < numprocs; source++) {
            MPI_Recv(message, 100, MPI_CHAR, source, 99,
                MPI_COMM_WORLD, &status);//接收的消息要保存在哪个变量,接收消息的个数(详细说明在上面),数据类型,接收哪个源进程的信息,tag,通信域,消息状态
            //tag和source可以使用通配符,如果source被设置为MPI_ANY_SOURCE,则通信域中的任何一个进程都能成为消息源。如果tag设置为MPI_ANY_TAG,那么任何标志的消息都能被接收
            //如果用户指定的接收缓冲区长度小于接收的消息,MPI直接返回一个overflow错。Status对象由用户分配,它向用户返回一些状态信息
            printf("接收到第%d号进程发送的消息:%s\n", source, message);
        }
    }
    MPI_Finalize();
    return 0;
} /* end main */

C中的数据类型

MPI_CHAR            

MPI_SHORT MPI_INT                        

MPI_LONG MPI_UNSIGNED_CHAR    

MPI_UNSIGNED_SHORT MPI_UNSIGNED        

MPI_UNSIGNED_LONG MPI_FLOAT            

MPI_DOUBLE MPI_LONG_DOUBLE                

MPI_BYTE MPI_PACKED

MPI提供对非阻塞通信的支持,使用户获取性能上的好处。

一个完整的MPI的非阻塞通信过程包括两个分离的阶段:

非阻塞地提交通信请求 ;

在某个时机再去阻塞地确认它的完成

MPI_Isend提交一个标准模式的发送,向用户返回一个发送请求的handle,该handle使用户可以查询该发送请求的状态,并且完成该发送请求。

MPI_Isend的返回仅意味着消息已经在发送中,此时用户不可以重用消息的发送缓冲区,直到显式地用MPI_Test或MPI_Wait阻塞地完成消息发送为止。 

MPI_Irecv提交一个接收请求,并向用户返回一个指向该请求的handle,该handle使用户可以查询该接收请求的状态,并且完成该接收请求。

MPI_Irecv的返回仅意味着消息已经在接收,此时用户不可以使用消息的接收缓冲区,直到显式地用MPI_Test或MPI_Wait阻塞地完成消息接收为止. 

MPI_Wait阻塞等待指定的请求操作完成。

当request对象标识的非阻塞操作完后,MPI_Wait返回,并且 MPI_Wait释放request对象,将其置为MPI_REQUEST_NULL。

status对象返回时包含了被完成操作的一些信息。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值