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

0

В (серии) попыток изучить одностороннюю связь 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();
}
Теги:
mpi
asynchronous
mpi-rma

1 ответ

1
Лучший ответ

Звонки в MPI RMA должны попадать парами - первый запускает эпоху доступа/экспозиции, а второй ее завершает:

 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 на вызов разблокировки.

  • 0
    Спасибо за четкий ответ. Я использовал барьер и теперь все процессы возвращают одинаковое количество. Тем не менее, иногда я все еще получаю странные счета, такие как 26 или 27 . Думаю, это требует мьютекса, как вы предложили на мои другие вопросы.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню