LoginSignup
2
2

More than 5 years have passed since last update.

MPIでの動的配列クラス(std::vector)の送信(MPI_Bcast)

Last updated at Posted at 2016-10-01

※この記事では,Ubuntu14.04サーバにインストールしたmpic++コンパイラで実行しています.

C++でのMPIの送信において,動的配列クラスvectorをやりとりする方法についてメモ.
Bcastでの送信にあたっては,プロセス間で送信(受信)する配列のサイズが一致している必要があるため,若干注意が必要です.

なお,MPIの基本関数については,このあたりで学びました.
MPIリファレンス:http://www.cv.titech.ac.jp/~hiro-lab/study/mpi_reference/index.html

まず,冒頭の共通部分はこちら.

#include <mpi.h>
#include <vector>
using namespace std;
int main(int argc, char** argv){
    MPI_Init(&argc, &argv); //MPI開始
    int rank, procs;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &procs);
    const int SIZE = 10;  //配列確保に使用

(1) まず,下記のような静的配列であれば特に問題は生じません.

1.
    int dat[SIZE]; // 静的配列の確保
    if(rank==0){  // プロセス0でデータを格納
        for(int i = 0; i < SIZE; i++){
            dat[i] = i;
        }
    }
    MPI_Bcast(&dat[0], SIZE, MPI_INT, 0, MPI_COMM_WORLD); //プロセス0から他のプロセスへ送信

&dat[0]はdat.data()でも代用可能ですが,環境によってはうまく動かないので,&dat[0]で記述します.

(2) 次に,動的配列でそのまま入れ替えると,下記のようになりますが,うまくいきません.

2.
    std::vector<int> dat; // 動的配列の宣言
    if(rank==0){
        for(int i = 0; i < SIZE; i++){
            dat.push_back(i);
        }
    }
    MPI_Bcast(&dat[0], SIZE, MPI_INT, 0, MPI_COMM_WORLD);

全プロセスでdatを宣言していますが,プロセス0でのpush_back後は,プロセス0と他のプロセスの配列datの長さは変わっているので,実行できません.” Signal: Segmentation fault (11)”などのエラーがでます.

(3) 元から,動的配列の長さを指定してしまえば,計算可能です.

3.
    std::vector<int> dat(SIZE); // 長さを指定した動的配列の宣言
    if(rank==0){
        for(int i = 0; i < SIZE; i++){
            dat[i] = i;
        }
    }
    MPI_Bcast(&dat[0], dat.size(), MPI_INT, 0, MPI_COMM_WORLD);

こちらは実行できますが,push_backは使えません(せっかくのvectorが,,最終行で,SIZEではなく,dat.size()で代替はしていますが,,)

(4) push_backを終えたあとに,配列の長さを全てのプロセスで揃えればよいので,

4-1.
    std::vector<int> dat;
    if(rank==0){
        for(int i = 0; i < SIZE; i++){
            dat.push_back(i);
        }
    }
    dat.resize(SIZE); // 各プロセスで配列の長さを指定
    MPI_Bcast(&dat[0], dat.size(), MPI_INT, 0, MPI_COMM_WORLD);
4-2.
    std::vector<int> dat;
    if(rank==0){
        for(int i = 0; i < SIZE; i++){
            dat.push_back(i);
        }
    }
    int size0 = dat.size(); // 配列の長さを取得
    MPI_Bcast(&size0, 1, MPI_INT, 0, MPI_COMM_WORLD); // プロセス0から他プロセスへ長さを送信
    dat.resize(size0); // 各プロセスで配列の長さを指定
    MPI_Bcast(&dat[0], dat.size(), MPI_INT, 0, MPI_COMM_WORLD);

4-1は結局int SIZEを利用しているので,たいして3と変わらないか..
4-2が応用しやすいとは思います.通信回数は2回に増えてしまいますが.

以上,まだまだ勉強中の身ですが,躓いた部分の試行錯誤の結果を整理しました.

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2