※この記事では,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) まず,下記のような静的配列であれば特に問題は生じません.
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) 次に,動的配列でそのまま入れ替えると,下記のようになりますが,うまくいきません.
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) 元から,動的配列の長さを指定してしまえば,計算可能です.
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を終えたあとに,配列の長さを全てのプロセスで揃えればよいので,
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);
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回に増えてしまいますが.
以上,まだまだ勉強中の身ですが,躓いた部分の試行錯誤の結果を整理しました.