Как отправить массив в стиле 2d C через Boost :: MPI?

я имею double A[B_ROWS][B_COLUMNS]; в C API я использовал stufflike:

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, а не какой-либо логики.

Итак, как правильно посылать массивы в стиле 2d C через boost :: mpi?

2

Решение

Если предположить, что мое слепое предположение верно, а то, что вы напечатали выше, является точным, то размер A не имеет ничего общего с A_COLUMNS (вместо, A имеет B_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);
}

Приведенный выше код для одно- и двухмерных массивов определит, сколько копий T вы действительно хотите отправить, вместо того, чтобы поддерживать его вручную.

Это даже работает на ломтики, как &A[low_bound], upper_bound-lower_bound,

Одна вещь, о которой вы, возможно, захотите быть осторожной, это пройти через конец массива. Вполне возможно, что ваш 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);
}

в этом случае вы передаете массив напрямую, а затем говорите, где хотите начать и закончить чтение. Преимущество состоит в том, что я проверяю, что массив действительно содержит данные для отправки или место для данных, чтобы прибыть.

(Эти две функции полагаются на функции выше)

В распределенной ситуации вы захотите создать механизм регистрации для ваших утверждений, который будет описательным.

Вот пример использования вышеуказанного кода:

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.

1

Другие решения

Других решений пока нет …