在尝试学习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 :(得分:1)
MPI的RMA中的围栏调用应成对出现 - 第一个启动访问/暴露时代,第二个启动它:
MPI_Win_fence(0, win);
...
MPI_Win_fence(0, win);
该标准明确警告不要使用fence调用而不是使用fence:
但是,调用
MPI_WIN_FENCE
已知不会结束任何时代(特别是与assert = MPI_MODE_NOPRECEDE
的通话)并不一定会成为障碍。
此外,围栏用于活动目标通信,不应与被动目标通信操作混合使用,例如MPI_Win_lock
。
解决方案:将MPI_Win_fence
的号码替换为MPI_COMM_WORLD
上的屏障。
另请注意,您的实施中存在错误 - 当您将窗口锁定在等级val->hostrank
时,您总是将0
的等级传递给解锁通话。