我试图通过一个小例子来理解MPI-Function`MPI_Fetch_and_op(),并遇到了一个我想理解的奇怪行为。
在该示例中,等级0的过程等待,直到过程1..4在进行之前每个都将结果的值增加1。
对于函数0
中使用的断言的默认值MPI_Win_lock_all()
,我有时(十分之一)得到无限循环,即更新MASTER中result[0]
的值值为3.终端输出类似于以下代码片段:
result: 3
result: 3
result: 3
...
根据文档,函数MPI_Fetch_and_op是原子的。
此操作相对于其他"累积"是原子操作。 操作
第一个问题:
为什么不将result[0]
的值更新为4?
如果我将assert
的值更改为MPI_MODE_NOCHECK
,它似乎可以正常工作
第二个问题:
为什么它与MPI_MODE_NOCHECK
根据文件,我认为这意味着必须以不同的方式组织互斥。有人可以解释MPI_Win_lock_all()
的文档中的段落吗?
MPI_MODE_NOCHECK
当调用者持有窗口锁定时,没有其他进程成立,或者将尝试获取冲突的锁定。这很有用 互斥是通过其他方式实现的,但是连贯性 可能附加到锁定和解锁呼叫的操作仍然是 必需的。
提前致谢!
示例程序:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#define MASTER 0
int main(int argc, char *argv[])
{
MPI_Init(&argc, &argv);
MPI_Comm comm = MPI_COMM_WORLD;
int r, p;
MPI_Comm_rank(comm, &r);
MPI_Comm_size(comm, &p);
printf("Hello from %d\n", r);
int result[1] = {0};
//int assert = MPI_MODE_NOCHECK;
int assert = 0;
int one = 1;
MPI_Win win_res;
MPI_Win_allocate(1 * sizeof(MPI_INT), sizeof(MPI_INT), MPI_INFO_NULL, comm, &result[0], &win_res);
MPI_Win_lock_all(assert, win_res);
if (r == MASTER) {
result[0] = 0;
do{
MPI_Fetch_and_op(&result, &result , MPI_INT, r, 0, MPI_NO_OP, win_res);
printf("result: %d\n", result[0]);
} while(result[0] != 4);
printf("Master is done!\n");
} else {
MPI_Fetch_and_op(&one, &result, MPI_INT, 0, 0, MPI_SUM, win_res);
}
MPI_Win_unlock_all(win_res);
MPI_Win_free(&win_res);
MPI_Finalize();
return 0;
}
使用以下Makefile编译:
MPICC = mpicc
CFLAGS = -g -std=c99 -Wall -Wpedantic -Wextra
all: fetch_and
fetch_and: main.c
$(MPICC) $(CFLAGS) -o $@ main.c
clean:
rm fetch_and
run: all
mpirun -np 5 ./fetch_and
答案 0 :(得分:1)
您的代码对我有效,没有变化。但这可能是巧合。您的代码有很多问题。让我指出我所看到的:
result[0] != 4
中的进程数进行了硬编码MPI_Fetch_and_op(&one, &result, MPI_INT, 0
MPI_Fetch_and_op(&result, &result
int**
(实际上是int (*)[1]
)result[0] = 0;
初始化窗口,但我认为这与窗口不一致,因此,再次您可能很幸运。MPI_Win_allocate(1 * sizeof(MPI_INT), sizeof(MPI_INT), MPI_INFO_NULL, comm, &result[0]
也会造成某种内存损坏,因为result
是此处的输出,但它是静态分配的数组。Win_free
试图取消分配内存缓冲区,但是,正如已经提到的那样,它是一个静态缓冲区,因此再次出现:内存损坏。Win_lock_all
是不合适的:这意味着一个进程将窗口锁定在所有目标上。没有任何竞争的锁!您仅将窗口锁定在一个进程上,而是将其锁定在所有可能的来源上。我会使用普通锁。Fetch_and_op
之后加上MPI_Win_flush_local
。好吧,所以这比理想的编程还少。不过,在我的设置中它仍然有效。 (有时。有时它也会挂起。)因此,您可能需要稍微清理一下代码。您的逻辑是正确的,但实际的实现却不正确。