2.3.2. MPI_Send と MPI_Recv

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <mpi.h>
#include <iostream>
#include <cstdlib>

/* 後で定義する関数の前方宣言 */
void send_data();
void recv_data();

/*
 * 2つのプロセスの間で配列データを送る
 *
 * 実行方法: mpiexec -n 2 mpi_sample2
 */
int main(int argc, char *argv[])
{
    MPI_Init(&argc, &argv);

    int num_procs;
    int my_rank;

    MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    if (num_procs != 2) {
        std::cerr << "Run this program in MPI with 2 processes." << std::endl;
        return EXIT_FAILURE;
    }

    // send data from rank 0 to rank 1
    if (my_rank == 0) {
        send_data();
    } else {
        recv_data();
    }

    MPI_Finalize();
    return EXIT_SUCCESS;
}

void send_data()
{
    double send_data[10];
    for (int i = 0; i < 10; i++) {
        send_data[i] = (double) i;
    }
    const double *data_address = &send_data[0];
    int data_count = 10;
    std::cout << "Sending data." << std::endl;
    std::cout << "send_data: [";
    for (int i = 0; i < 10; i++)
    {
        std::cout << " " << send_data[i];
    }
    std::cout << " ]" << std::endl;
    MPI_Send(
        data_address, /* データ(バッファ)の先頭アドレス。MPIはここから読み出すだけなのでconst */
        data_count, /* 要素数 */
        MPI_DOUBLE, /* 送るデータの型。バッファの型に合わせる。間違えると受信データがおかしくなる。 */
        1, /* 送り先のrank */
        0, /* タグと呼ぶ数値。同時期に同じ送信先に違う意味合いのデータを送る時に区別するための番号。自分で値を決める */
        MPI_COMM_WORLD /* ノードを用途別にグループ分けした時にグループを識別するための値 */
    );
}

void recv_data()
{
    double data[10];
    double *data_address = &data[0];
    int data_count = 10;
    MPI_Status st; /* 通信の成否コードを受け取るための変数 */

    std::cout << "Receiving data." << std::endl;
    MPI_Recv(
        data_address, /* データ(バッファ)の先頭アドレス。MPIはここに書き込むので非const */
        data_count, /* 受信するデータの個数。 */
        MPI_DOUBLE, /* 受信するデータの型。 */
        0, /* 送り元のrank */
        0, /* タグ */
        MPI_COMM_WORLD,
        &st
    );
    std::cout << "recv_data: [";
    for (int i = 0; i < 10; i++)
    {
        std::cout << " " << data[i];
    }
    std::cout << " ]" << std::endl;
}

Download the source code

この例では最も基本的な通信関数の MPI_Send と MPI_Recv を使っています。

プロセス数 2 で起動されると、rank 0 として起動されたプロセスの側では 送信を行い、rank 1 として起動されたプロセスの側では受信を行います。

このプログラムは 2 プロセスとして起動された場合にだけ対応しているので プログラムの入り口でプロセス数のチェックをしています。

送信データは配列として用意します。配列の先頭アドレス、送るデータの 要素数、データの型のコード、送り先相手などを指定して MPI_Send を呼びます。

受信側では受信データを受け取る配列を用意します。受信データの個数が 分かっていないと配列を用意できませんが、ここでは10個で固定になっています。 受信側も、送信側と似たような情報を指定して MPI_Recv を呼びます。

このサンプルのコンパイルと実行した例を示します。:

$ mpic++ -o mpi_sample2 mpi_sample2.cpp
$ mpiexec -n 2 mpi_sample2
Receiving data.
Sending data.
send_data: [ 0 1 2 3 4 5 6 7 8 9 ]
recv_data: [ 0 1 2 3 4 5 6 7 8 9 ]