MPI學習-點對點通信

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;
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章