订购问题sychronizing MPI-2单面通信(order issue in sychroni

2019-10-20 11:16发布

我学习MPI-2,并试图实现使用MPI-2片面通信的第一个简单的功能:

有进程0宿主固定大小的一个阵列data_size

每个进程(包括0)将产生一个阵列和与主机阵列比较:

如果所产生的阵列的第一个元素是比主体阵列的更小,更换主机阵列所生成的一个。

在代码:

vector<int> v1 = {rank,rank+1,rank+2};
v = get_vec(vec);
if (v1[0] < v[0])
    put_vec(vec,v1);

完整的代码是在底部。 我希望的,当然,在所有可产生阵列,所述一个具有最小头元件应该主机阵列中最后当程序完成,因为最小阵列([0,1,2]在此示例中)将取代其他并不会取代自己。

然而,在一些(罕见)情况下,我得到这样的输出:

$ mpiexec.exe -n 4 a.exe
#0 assigns v1 {0 ...} to host v {2 ...}
#1 assigns v1 {1 ...} to host v {2 ...}
 1  2  3

,这似乎表明,两项工作都在同一时间到主机的数据制成。 我想我必须有误解的锁定/解锁同步指令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;
}

Answer 1:

这是一个经典的数据竞争的情况。 无论get_vecput_vec单独锁定窗口,但实际上你需要的是跨越整个代码块,即锁:

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

按照目前,有可能的是,共享载体的含量可以在呼叫之后改变到get_vec()由于另一个进程执行put_vec()并且可以在比较的结果无效。 事情是这样的:

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;
}

功能compare_swap_vec()需要一个矢量,并使用它,如果低于关系成立,以取代共享矢量的旧内容。 它还返回向量的以前的内容。 vec->win_ext是由承载向量内容的相同进程承载另一个窗口。 它用于外锁由于MPI标准要求,对于在相同的工艺在同一个窗口不同的访问历元必须是不相交的,这是我解释为同一窗口上嵌套锁是不允许的。



文章来源: order issue in sychronizing MPI-2 one sided communication