我试图通过一个小例子来理解MPI函数`MPI_Fetch_and_op()并遇到我想理解的奇怪行为。
在示例中,等级为0的过程一直等待,直到过程1..4在执行之前各自将结果值增加1。
[在函数0
中使用断言的默认值MPI_Win_lock_all()
,有时我(10之1)会遇到无限循环,即将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
您的代码对我有用,没有变化。请注意:
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
是此处的输出,但它是静态分配的数组。