c++ - 使用 MPI-2 单向通信同步单个 int 值的问题

标签 c++ asynchronous mpi mpi-rma

在学习 MPI-2 单向通信的(一系列)尝试中,我正在测试以下代码,其中我在主进程中存储一个基本类型值,例如 int ,并将其暴露给所有其他进程。现在我对整数所做的事情很简单。我让每个进程迭代地增加它,直到共享整数达到最大值。每个进程在打印出共享整数之前都会进行fence,如下(完整代码在底部):

  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 的 RMA 中的栅栏调用应该成对出现——第一个开始访问/暴露时期,第二个完成它:

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

标准明确警告不要使用栅栏调用而不是障碍:

However, a call to MPI_WIN_FENCE that is known not to end any epoch (in particular, a call with assert = MPI_MODE_NOPRECEDE) does not necessarily act as a barrier.

此外,栅栏用于主动目标通信,不应与被动目标通信操作混合使用,例如MPI_Win_lock

解决方案:用 MPI_COMM_WORLD 上的屏障替换对 MPI_Win_fence 的调用。

此外,请注意您的实现中存在一个错误 - 当您将窗口锁定在等级 val->hostrank 时,您始终将等级 0 传递给解锁通话。

关于c++ - 使用 MPI-2 单向通信同步单个 int 值的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24874207/

相关文章:

C++/WinRT : Can I await a single IAsyncAction handle from multiple coroutine calls?

c# - 非线程安全函数异步安全吗?

c++ - 如何将单个char转换为int

c++ - 编译未解析的外部符号 gdcm::system::getHostName 等

c++ - 进程中 0 到 255 之间的唯一编号

c++ - 在 POSIX 操作系统上检测 SSD 存储设备

c# - 如何将松散耦合和可扩展的设计与可能的异步实现相结合?

c++ - 哪个带有 boost 的 mpi 存档?

mpi - MPI处理器数量?

mpi - isend 和 issend 和有什么不一样?