проблемы синхронизации одного значения int с односторонней связью MPI-2

В (серии) попыток изучить одностороннюю связь MPI-2 я тестирую следующий код, в котором я храню одно значение фундаментального типа, такое как int в мастер-процессе, и выставить его на все остальные процессы. Теперь то, что я делаю с целым числом, просто. У меня есть каждый процесс итеративно увеличивать его, пока общее целое число не достигнет максимального значения. Каждый процесс будет ограничен перед выводом общего целого числа, как показано ниже (полный код внизу):

  for (int i = 0; i < 10; i++) {
mpi_val_t<int>::inc_val(val,1);
if (mpi_val_t<int>::get_val(val) >= 25)
break;
}
MPI_Win_fence(0,val->win);
std::cout << "val = " << mpi_val_t<int>::get_val(val) << std::endl;

Я ожидаю, что каждый процесс будет печатать одно и то же значение (25) на выходе. Но иногда я получаю вывод, как это:

$ mpiexec.exe -n 4 a.exe
val = 17
val = 22
val = 25
val = 25

Кто-нибудь может объяснить, что здесь происходит и как правильно его синхронизировать?

Спасибо,


Код:

#include <mpi.h>
#include <cstdlib>
#include <cstdio>
#include <iostream>

template <typename T>
inline MPI_Datatype mpi_type();
template <> inline MPI_Datatype mpi_type<int>() { return MPI_INT; }
template <> inline MPI_Datatype mpi_type<double>() { return MPI_DOUBLE; }

template <typename T>
class mpi_val_t {
public:
MPI_Win win;
int  hostrank;  //id of the process that host the value to be exposed to all processes
int  rank;      //process id
int  size;      //number of processes
T    val;       //the shared value

static struct mpi_val_t *create_val(int hostrank, T v) {
struct mpi_val_t *val;

val = (struct mpi_val_t *)malloc(sizeof(struct mpi_val_t));
val->hostrank = hostrank;
MPI_Comm_rank(MPI_COMM_WORLD, &(val->rank));
MPI_Comm_size(MPI_COMM_WORLD, &(val->size));

if (val->rank == hostrank) {
MPI_Alloc_mem(sizeof(T), MPI_INFO_NULL, &(val->val));
val -> val = v;
MPI_Win_create(&val->val, sizeof(T), sizeof(T),
MPI_INFO_NULL, MPI_COMM_WORLD, &(val->win));
}
else {
MPI_Win_create(&val->val, 0, 1,
MPI_INFO_NULL, MPI_COMM_WORLD, &(val->win));
}
return val;
}

static void delete_val(struct mpi_val_t **val) {
MPI_Win_free(&((*val)->win));
free((*val));
*val = NULL;
return;
}

static T get_val(struct mpi_val_t *val) {
T ret;
MPI_Win_lock(MPI_LOCK_SHARED, val->hostrank, 0, val->win);
MPI_Get(&ret, 1 , mpi_type<T>(), val->hostrank, 0, 1, mpi_type<T>(), val->win);
MPI_Win_unlock(0, val->win);
return ret;
}

static void inc_val(struct mpi_val_t *val, T inc) {
MPI_Win_lock(MPI_LOCK_EXCLUSIVE, val->hostrank, 0, val->win);
MPI_Accumulate(&inc, 1, mpi_type<T>(), val->hostrank, 0, 1, mpi_type<T>(), MPI_SUM,val->win);
MPI_Win_unlock(0, val->win);
}

}; //mpi_val_t

int main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
mpi_val_t<int>* val = mpi_val_t<int>::create_val(0,0);
for (int i = 0; i < 10; i++) {
mpi_val_t<int>::inc_val(val,1);
if (mpi_val_t<int>::get_val(val) >= 25)
break;
}
MPI_Win_fence(0,val->win);
std::cout << "val = " << mpi_val_t<int>::get_val(val) << std::endl;
mpi_val_t<int>::delete_val(&val);
MPI_Finalize();
}

0

Решение

Вызовы забора в RMA MPI должны приходить парами — первый начинает эпоху доступа / воздействия, а второй завершает ее:

 MPI_Win_fence(0, win);
...
MPI_Win_fence(0, win);

Стандарт явно предупреждает против использования вызовов забора вместо барьеров:

Тем не менее, призыв к MPI_WIN_FENCE которая, как известно, не заканчивается ни одной эпохи (в частности, assert = MPI_MODE_NOPRECEDE) не обязательно выступает в качестве барьера.

Кроме того, заборы используются для активное целевое общение и не следует смешивать с пассивное целевое общение такие операции, как MPI_Win_lock,

Решение: заменить вызов на MPI_Win_fence с барьером на MPI_COMM_WORLD,

Также обратите внимание, что в вашей реализации есть ошибка — пока вы блокируете окно в ранге val->hostrankты всегда получаешь звание 0 на вызов разблокировки.

1

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


По вопросам рекламы [email protected]