C++ 同步MPI-2单边通信中的订单问题

C++ 同步MPI-2单边通信中的订单问题,c++,synchronization,mpi,mpi-rma,C++,Synchronization,Mpi,Mpi Rma,我正在学习MPI-2,并尝试使用MPI-2单边通信实现第一个简单功能: 让进程0承载一个固定大小的数组数据大小 每个进程(包括0)将生成一个数组并与主机数组进行比较: 如果生成的阵列的第一个元素小于主机阵列的第一个元素,请使用生成的阵列替换主机阵列 代码: vector<int> v1 = {rank,rank+1,rank+2}; v = get_vec(vec); if (v1[0] < v[0]) put_vec(vec,v1); ,这似乎表明对主机数据同时进行

我正在学习MPI-2,并尝试使用MPI-2单边通信实现第一个简单功能:

让进程0承载一个固定大小的数组
数据大小

每个进程(包括0)将生成一个数组并与主机数组进行比较:

如果生成的阵列的第一个元素小于主机阵列的第一个元素,请使用生成的阵列替换主机阵列

代码:

vector<int> v1 = {rank,rank+1,rank+2};
v = get_vec(vec);
if (v1[0] < v[0])
    put_vec(vec,v1);
,这似乎表明对主机数据同时进行了两次赋值。我想我一定误解了
get_vec/putvec
中的锁定/解锁同步指令,或者在其他地方犯了一些明显的错误

有人能解释一下我应该如何修复代码以获得预期的输出吗

提前谢谢


使用g++-std=c++11 test.cpp-lmpi编译的完整代码:

#include <mpi.h>
#include <stdlib.h>
#include <stdio.h>
#include <thread>
#include <chrono>

#include <iostream>
#include <vector>

using namespace std;


struct mpi_vector_t {
  MPI_Win win;
  int  hostrank;  //id of the process that host values to be exposed to all processes
  int  rank;    //process id
  int  size;     //number of processes
  int  *data;
  int  data_size;
};

struct mpi_vector_t *create_vec(int hostrank, std::vector<int> v) {
    struct mpi_vector_t *vec;

    vec = (struct mpi_vector_t *)malloc(sizeof(struct mpi_vector_t));
    vec->hostrank = hostrank;
    vec->data_size = v.size();
    MPI_Comm_rank(MPI_COMM_WORLD, &(vec->rank));
    MPI_Comm_size(MPI_COMM_WORLD, &(vec->size));

    if (vec->rank == hostrank) {
        MPI_Alloc_mem(vec->data_size * sizeof(int), MPI_INFO_NULL, &(vec->data));
        for (int i=0; i<vec->size; i++) vec->data[i] = v[i];
        MPI_Win_create(vec->data, vec->data_size * sizeof(int), sizeof(int),
                       MPI_INFO_NULL, MPI_COMM_WORLD, &(vec->win));
    }
    else {
        vec->data = NULL;
        vec->data_size = v.size();
        MPI_Win_create(vec->data, 0, 1,
                       MPI_INFO_NULL, MPI_COMM_WORLD, &(vec->win));
    }
    return vec;
}

void delete_vec(struct mpi_vector_t **count) {
    if ((*count)->rank == (*count)->hostrank) {
        MPI_Free_mem((*count)->data);
    }
    MPI_Win_free(&((*count)->win));
    free((*count));
    *count = NULL;

    return;
}

std::vector<int> get_vec(struct mpi_vector_t *vec) {
    vector<int> ret(vec->data_size);
    MPI_Win_lock(MPI_LOCK_SHARED, vec->hostrank, 0, vec->win);
    MPI_Get(&ret.front(), vec->data_size, MPI_INT, vec->hostrank, 0, vec->data_size, MPI_INT, vec->win);
    MPI_Win_unlock(0, vec->win);
    return ret;
}

void put_vec(struct mpi_vector_t *vec, std::vector<int> v) {
    MPI_Win_lock(MPI_LOCK_EXCLUSIVE, vec->hostrank, 0, vec->win);
    MPI_Put(&v.front(), vec->data_size, MPI_INT, vec->hostrank, 0, vec->data_size, MPI_INT, vec->win);
    MPI_Win_unlock(0, vec->win);
}

void print_vec(struct mpi_vector_t *vec) {
    if (vec->rank == vec->hostrank) {
        for (int i=0; i<vec->data_size; i++) {
            printf("%2d ", vec->data[i]);
        }
        puts("");
    }
}


int main(int argc, char **argv) {

    MPI_Init(&argc, &argv);

    struct mpi_vector_t *vec;
    int rank;

    vector<int> v = {2,3,1};
    vec = create_vec(0, v);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    for (int itest = 0; itest < 2; itest++) {
        vector<int> v1 = { rank, rank + 1, rank + 2 }; //some generated data
        v = get_vec(vec);
        if (v1[0] < v[0]) {
            cout << "#" << rank << " assigns v1 {" << v1[0] <<
                    " ...} to host v {" << v[0] << " ...}" << endl;
            put_vec(vec, v1);
        }
    }

    MPI_Barrier(MPI_COMM_WORLD);
    print_vec(vec);
    delete_vec(&vec);

    MPI_Finalize();
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
结构mpi\u向量{
MPI_Win Win;
int hostrank;//承载要向所有进程公开的值的进程的id
int rank;//进程id
int size;//进程数
int*数据;
int数据大小;
};
结构mpi_vector_t*create_vec(int hostrank,std::vector v){
结构mpi_vector_t*vec;
vec=(结构mpi_向量t*)malloc(sizeof(结构mpi_向量t));
vec->hostrank=hostrank;
向量->数据大小=v.大小();
MPI通信等级(MPI通信世界和(vec->rank));
MPI通信大小(MPI通信世界和(vec->size));
如果(向量->秩==主机秩){
MPI_Alloc_mem(vec->data_size*sizeof(int),MPI_INFO_NULL,&(vec->data));
对于(inti=0;isize;i++)vec->data[i]=v[i];
MPI_Win_create(vec->data,vec->data_size*sizeof(int),sizeof(int),
MPI_INFO_NULL、MPI_COMM_WORLD和(vec->win));
}
否则{
vec->data=NULL;
向量->数据大小=v.大小();
MPI\u Win\u创建(向量->数据,0,1,
MPI_INFO_NULL、MPI_COMM_WORLD和(vec->win));
}
返回向量;
}
无效删除向量(结构mpi向量**计数){
如果((*count)->rank==(*count)->hostrank){
MPI自由内存((*计数)->数据);
}
MPI_Win_free(&((*count)->Win));
自由((*计数));
*计数=空;
返回;
}
std::vector get_vec(结构mpi_vector_t*vec){
向量ret(向量->数据大小);
MPI_Win_lock(MPI_lock_SHARED,vec->hostrank,0,vec->Win);
MPI_-Get(&ret.front(),vec->data_-size,MPI_-INT,vec->hostrank,0,vec->data_-size,MPI_-INT,vec->win);
MPI_Win_解锁(0,vec->Win);
返回ret;
}
void put_vec(结构mpi_vector_t*vec,std::vector v){
MPI_Win_lock(MPI_lock_独占,vec->hostrank,0,vec->Win);
MPI_Put(&v.front(),vec->data_size,MPI_INT,vec->hostrank,0,vec->data_size,MPI_INT,vec->win);
MPI_Win_解锁(0,vec->Win);
}
无效打印向量(结构mpi向量*vec){
如果(vec->rank==vec->hostrank){
对于(int i=0;idata_size;i++){
printf(“%2d”,向量->数据[i]);
}
认沽权(“”);
}
}
int main(int argc,字符**argv){
MPI_Init(&argc,&argv);
结构mpi_vector_t*vec;
整数秩;
向量v={2,3,1};
向量=创建向量(0,v);
MPI通信等级(MPI通信世界和等级);
for(int-itest=0;itest<2;itest++){
向量v1={rank,rank+1,rank+2};//一些生成的数据
v=获取向量(向量);
if(v1[0]cout这是一个经典的数据竞争场景。
get_-vec
put_-vec
分别锁定窗口,但实际上需要一个跨越整个代码块的锁,即:

lock_window();
v = get_vec(vec);
if (v1[0] < v[0])
   put_vec(vec,v1);
unlock_window();

函数
compare\u swap\u vec()
获取一个向量,如果小于关系成立,则使用它替换共享向量的旧内容。它还返回向量的以前内容。
vec->win_ext
是另一个由承载向量内容的同一进程托管的窗口。它用于外部锁,因为MPI标准要求不同的acc同一进程中同一窗口的ess时代必须是不相交的,我将其解释为不允许在同一窗口上嵌套锁。

你完全正确。但是,在使用
MPI\u Put
中检索到的内容之前,单边通信是否特别需要在
MPI\u Get
调用后执行同步操作(等待asyc.op完成)?或者MPI-2是否表示这种组合应该可以?谢谢。虽然我关于在两次调用期间必须锁定窗口的说明是正确的,但我忽略了一个事实,即
MPI\u Get
MPI\u Put
都是非阻塞的,并且它们保证只在访问周期结束时完成,这意味着外部ock必须位于另一个窗口上。您可能可以使用此窗口。非常感谢您的指针。我现在对互斥体了解不够,但我相信这是正确的方向。
lock_window();
v = get_vec(vec);
if (v1[0] < v[0])
   put_vec(vec,v1);
unlock_window();
std::vector<int> compare_swap_vec(struct mpi_vector_t *vec, std::vector v) {
    vector<int> ret(vec->data_size);
    MPI_Win_lock(MPI_LOCK_EXCLUSIVE, vec->hostrank, 0, vec->win_ext);
    ret = get_vec(vec);
    if (v[0] < ret[0])
        put_vec(vec, v);
    MPI_Win_unlock(0, vec->win_ext);
    return ret;
}