2.3.2. MPI_Send と MPI_Recv

 1#include <mpi.h>
 2#include <iostream>
 3#include <cstdlib>
 4
 5/* 後で定義する関数の前方宣言 */
 6void send_data();
 7void recv_data();
 8
 9/*
10 * 2つのプロセスの間で配列データを送る
11 *
12 * 実行方法: mpiexec -n 2 mpi_sample2
13 */
14int main(int argc, char *argv[])
15{
16    MPI_Init(&argc, &argv);
17
18    int num_procs;
19    int my_rank;
20
21    MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
22    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
23
24    if (num_procs != 2) {
25        std::cerr << "Run this program in MPI with 2 processes." << std::endl;
26        return EXIT_FAILURE;
27    }
28
29    // send data from rank 0 to rank 1
30    if (my_rank == 0) {
31        send_data();
32    } else {
33        recv_data();
34    }
35
36    MPI_Finalize();
37    return EXIT_SUCCESS;
38}
39
40void send_data()
41{
42    double send_data[10];
43    for (int i = 0; i < 10; i++) {
44        send_data[i] = (double) i;
45    }
46    const double *data_address = &send_data[0];
47    int data_count = 10;
48    std::cout << "Sending data." << std::endl;
49    std::cout << "send_data: [";
50    for (int i = 0; i < 10; i++)
51    {
52        std::cout << " " << send_data[i];
53    }
54    std::cout << " ]" << std::endl;
55    MPI_Send(
56        data_address, /* データ(バッファ)の先頭アドレス。MPIはここから読み出すだけなのでconst */
57        data_count, /* 要素数 */
58        MPI_DOUBLE, /* 送るデータの型。バッファの型に合わせる。間違えると受信データがおかしくなる。 */
59        1, /* 送り先のrank */
60        0, /* タグと呼ぶ数値。同時期に同じ送信先に違う意味合いのデータを送る時に区別するための番号。自分で値を決める */
61        MPI_COMM_WORLD /* ノードを用途別にグループ分けした時にグループを識別するための値 */
62    );
63}
64
65void recv_data()
66{
67    double data[10];
68    double *data_address = &data[0];
69    int data_count = 10;
70    MPI_Status st; /* 通信の成否コードを受け取るための変数 */
71
72    std::cout << "Receiving data." << std::endl;
73    MPI_Recv(
74        data_address, /* データ(バッファ)の先頭アドレス。MPIはここに書き込むので非const */
75        data_count, /* 受信するデータの個数。 */
76        MPI_DOUBLE, /* 受信するデータの型。 */
77        0, /* 送り元のrank */
78        0, /* タグ */
79        MPI_COMM_WORLD,
80        &st
81    );
82    std::cout << "recv_data: [";
83    for (int i = 0; i < 10; i++)
84    {
85        std::cout << " " << data[i];
86    }
87    std::cout << " ]" << std::endl;
88}

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 ]