MPI学习-点对点通信

来源:互联网 发布:ubuntu find命令 编辑:程序博客网 时间:2024/05/16 15:13

MPI通信类型:

  • 点对点通信
  • 聚合通信

点对点通信:

  • 同一通信器内的两个进程之间的消息传递;
  • 分为阻塞型、非阻塞型通信。

本文主要学习点对点通信

MPI点对点消息发送模式

  • 标准模式(学习重点)

    自由发送接收,不考虑其它进程状态;

  • 缓存模式

    由用户显式提供缓存区,辅助通信;创建、释放缓存区:

    MPI_Buffer_attach(buffer, size);
    MPI_Buffer_detach(buffer, size);

  • 同步模式

    通信双方先建立联系,再通信;

  • 就绪模式

    接受进程必须先于发送进程提出通信要求;

    通信函数


MPI标准阻塞通信函数

MPI消息由消息信封消息数据组成

int MPI_Send(void *send_buffer,/*指向包含消息内容的内存块的指针 */int send_count,/*数据量*/MPI_Datatype datatype,/*数据类型*/int dest,/*要接收消息的进程的进程号*/int tag,/*tag=0,表示消息是要打印的;tag=1,表示消息是要用于计算的*/MPI_Comm comm);/*通信器,指定通信范围*/

前三项为待发送的消息数据,后三项为消息信封(接收者的地址)。

int MPI_Recv(void *recv_buffer,int recv_count,MPI_Datatype datatype,int source,int tag,MPI_Comm comm,MPI_Status * status);

注:
1.若接收多个进程传来的消息,int source使用常量MPI_ANY_SOURCE则可以按照进程完成工作的顺序来接收结果,避免等待;

2.Recv的tag要与Send的tag相匹配;

3.若一个进程接收多条来自另一个进程的有着不同tag的消息,可将常量MPI_ANY_TAG传递给tag

4.status简介

类型为MPI_Status的结构体,至少有以下三个成员

  • status.MPI_SOURCE

  • status.MPI_TAG

  • status.MPI_ERROR

    &status作为最后一个参数传递给Recv函数并调用它后,可以通过检查结构体中的成员来确定发送者source和标签tag。

进一步解释
MPI_Send发送过程:

1.发送进程组装消息(包括数据信封

2.缓冲消息/阻塞

  • 缓冲消息:MPI把消息放置在自己内部存储器里,并返回MPI_Send调用;
  • 阻塞(block):发送进程一直等待,直到可以发送消息,并不立即返回MPI_Send调用;

MPI_Recv接收过程:

总是阻塞的直到接收到一条匹配的信息。

陷阱

  • 若MPI_Send发生阻塞,并且没有相匹配的进程接收,那么发送进程悬挂
  • 若MPI_Send缓冲,但没有相匹配的接收,那么信息丢失。

用MPI实现梯形积分

        /*        梯形积分法,计算y=sin x 在[0,pi]上的积分        @ trap 梯形积分串行程序        @total_inte 最终积分结果        */        #include "stdafx.h"        #include <stdio.h>        #include <stdlib.h>        #include <string.h>        #include <iostream>        #include<math.h>        #include "mpi.h"        using namespace std;        const double a = 0.0;        const double b = 3.1415926;        int n = 100;        double h = (b - a) / n;        double trap(double a, double b, int n, double h)        {            double*x = new double[n + 1];            double*f = new double[n + 1];            double inte = (sin(a) + sin(b)) / 2;            for (int i = 1; i<n + 1; i++) {                x[i] = x[i - 1] + h;   /*x_0=a,x_n=b*/                f[i] = sin(x[i]);                inte += f[i];            }            inte = inte*h;    /* inte=h*[f(a)/2+f(x_1)+...f(x_{n-1})+f(b)/2]*/            return inte;        }        int main(int argc, char * argv[])        {            int myid, nprocs;            int local_n;            double local_a;            double local_b;            double total_inte;            MPI_Init(&argc, &argv);            MPI_Comm_rank(MPI_COMM_WORLD, &myid);   /* get current process id */            MPI_Comm_size(MPI_COMM_WORLD, &nprocs); /* get number of processes */            local_n = n / nprocs;            local_a = a + myid*local_n*h;            local_b = local_a + local_n*h;            double local_inte = trap(local_a, local_b, local_n, h);            if (myid != 0)            {                MPI_Send(&local_inte, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);            }            else            {                total_inte = local_inte;                for (int i = 1; i<nprocs; i++)                {                    MPI_Recv(&local_inte, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);                    total_inte += local_inte;                }            }            if (myid == 0)            {                printf("integral output is %d", total_inte);            }            MPI_Finalize();            return 0;        }
0 0