2

私はdouble A[B_ROWS][B_COLUMNS];CAPIで次のようなものを使用しました:

MPI_Isend(&A[low_bound][0], (upper_bound - low_bound) * A_COLUMNS, MPI_DOUBLE, i, MASTER_TO_SLAVE_TAG + 2, MPI_COMM_WORLD, &request);

 MPI_Recv(&A[low_bound][0], (upper_bound - low_bound) * A_COLUMNS, MPI_DOUBLE, 0, MASTER_TO_SLAVE_TAG + 2, MPI_COMM_WORLD, &status);

ブースト::mpiで私は試します:

world.isend(i, TO_SLAVE_TAG + 2, &A[low_bound][0], (upper_bound - low_bound) * A_COLUMNS);

world.recv(0, TO_SLAVE_TAG + 2, &A[low_bound][0], (upper_bound - low_bound) * A_COLUMNS);

しかし、私のアプリは常に次のようなもので失敗します:

rank 1 in job 10  master_39934   caused collective abort of all ranks
  exit status of rank 1: killed by signal 11

つまりseg fault、元のCアプリは必要に応じて機能し、現在変更したのはapiの使用だけであり、ロジックは使用されていないことに注意してください。

では、boost ::mpiを介して2DCスタイルの配列を送信する正しい方法は何ですか?

4

1 に答える 1

1

私の盲目的な推測が正しく、上で入力した内容が正確であると仮定すると、のサイズは(ではなく)とはA関係ありません。もしそうなら、以下のコードはその種の「非同期」エラーを修正します:A_COLUMNSAB_COLUMNS

template<typename World, typename T>
void isend( World& w, int dest, int tag, T const* t, size_t n = 1) {
  world.isend(dest, tag, &t, n);
}
template<typename World, typename T, size_t aSize>
void isend( World& w, int dest, int tag, T const (*arr1)[aSize], size_t n = 1) {
  world.isend(dest, tag, &(*arr)[0], n*aSize);
}
template<typename World, typename T, size_t aSize, size_t bSize>
void isend( World& w, int dest, int tag, T const (*arr2)[aSize][bSize], size_t n = 1) {
  world.isend(dest, tag, &(*arr)[0][0], n*aSize*bSize);
}

template<typename World, typename T>
void recv( World& w, int dest, int tag, T* t, size_t n = 1) {
  world.recv(dest, tag, &t, n);
}
template<typename World, typename T, size_t aSize>
void recv( World& w, int dest, int tag, T (*arr1)[aSize], size_t n = 1) {
  world.recv(dest, tag, &(*arr)[0], n*aSize);
}
template<typename World, typename T, size_t aSize, size_t bSize>
void recv( World& w, int dest, int tag, T (*arr2)[aSize][bSize], size_t n = 1) {
  world.recv(dest, tag, &(*arr)[0][0], n*aSize*bSize);
}

上記のコードは、1次元および2次元配列の場合、手動で保守する代わりに、実際に送信するTのコピーの数を計算します。

のようなスライスでも機能し&A[low_bound], upper_bound-lower_boundます。

注意したいことの1つは、配列の終わりを超えて吹き飛ばすことです。Cコードが配列の終わりを超えた可能性は簡単にありますが、そこには重要なものがなかったため、存続しました。C ++コードでは、そこにオブジェクトを置くことができ、生き残る代わりに死にます。

別のアプローチは、次のように、スライスの上限と下限の両方をとる関数を作成することです。

template<typename World, typename T, size_t N>
void isend_slice( World& w, int dest, int tag, T const (&t)[N], size_t start=0, size_t end=N ) {
  Assert( end <= N && start < end );
  isend(world, dest, tag, &(t[start]), end-start);
}
template<typename World, typename T, size_t N>
void recv_slice( World& w, int dest, int tag, T (&t)[N], size_t start=0, size_t end=N ) {
  Assert( end <= N && start < end );
  recv(world, dest, tag, &(t[start]), end-start);
}

この場合、配列を直接渡してから、読み取りを開始および終了する場所を指定します。利点は、アレイに実際に送信するデータがあること、またはデータが到着する余地があることを確認することです。

(これらの2つの関数は、上記の関数に依存しています)

分散した状況では、説明的なアサートのロギングメカニズムを作成する必要があります。

上記のコードの使用例は次のとおりです。

int array[10];
int array2[10][10];
isend(world, dest, tag+0, &int(7)); // tag is an int
isend(world, dest, tag+1, &array); // tag+1 is a 10 int array
isend(world, dest, tag+2, &array2); // tag+2 is a 100 int array
isend(world, dest, tag+1, &(array2[5])); // tag+1 is a 10 int array
isend_slice(world, tag+3, 0, array2, 7, 11); // asserts, but its a 40 int array

とrecvの同上。

于 2012-12-14T20:00:35.190 に答える