【问题标题】:How to send 2d C style array over Boost::MPI?如何通过 Boost::MPI 发送 2d C 样式数组?
【发布时间】:2012-11-26 05:44:57
【问题描述】:

我在 C API 中有 double A[B_ROWS][B_COLUMNS]; 我使用过类似的东西:

MPI_Isend(&A[low_bound][0], (upper_bound - low_bound) * A_COLUMNS, MPI_DOUBLE, i, MASTER_TO_SLAVE_TAG + 2, MPI_COMM_WORLD, &request);

 MPI_Recv(&A[low_bound][0], (upper_bound - low_bound) * A_COLUMNS, MPI_DOUBLE, 0, MASTER_TO_SLAVE_TAG + 2, MPI_COMM_WORLD, &status);

现在with boost::mpi我试试:

world.isend(i, TO_SLAVE_TAG + 2, &A[low_bound][0], (upper_bound - low_bound) * A_COLUMNS);

world.recv(0, TO_SLAVE_TAG + 2, &A[low_bound][0], (upper_bound - low_bound) * A_COLUMNS);

但我的应用经常出现以下问题:

rank 1 in job 10  master_39934   caused collective abort of all ranks
  exit status of rank 1: killed by signal 11

这意味着seg fault,请注意原始 C 应用程序可以根据需要运行,而我目前更改的只是使用 api - 没有任何逻辑。

那么通过 boost::mpi 发送 2d C 样式数组的正确方法是什么?

【问题讨论】:

  • 如果value参数是可序列化类型会更好。
  • 可能是愚蠢的建议:你不应该有(upper_bound - low_bound + 1) * A_COLUMNS,加上那个+1吗?或者upper_bound==low_bound 时有 0 是否正确?
  • sscce.org -- 我们能得到一份你的程序的副本,它实际演示了问题并编译了吗?我的意思是,我可以指出AA_COLUMNS 无关,因为您的Adouble A[B_ROWS][B_COLUMNS] 类型——注意Bs。但这可能只是您没有真正描述您遇到的问题,而不是代码中的基本问题。

标签: c++ c boost mpi boost-mpi


【解决方案1】:

假设我的盲目猜测是正确的,并且您在上面输入的内容是准确的,A 的大小与A_COLUMNS 无关(相反,A 具有B_COLUMNS)。如果是这样,下面的代码将修复这种“不同步”错误:

template<typename World, typename T>
void isend( World& w, int dest, int tag, T const* t, size_t n = 1) {
  world.isend(dest, tag, &t, n);
}
template<typename World, typename T, size_t aSize>
void isend( World& w, int dest, int tag, T const (*arr1)[aSize], size_t n = 1) {
  world.isend(dest, tag, &(*arr)[0], n*aSize);
}
template<typename World, typename T, size_t aSize, size_t bSize>
void isend( World& w, int dest, int tag, T const (*arr2)[aSize][bSize], size_t n = 1) {
  world.isend(dest, tag, &(*arr)[0][0], n*aSize*bSize);
}

template<typename World, typename T>
void recv( World& w, int dest, int tag, T* t, size_t n = 1) {
  world.recv(dest, tag, &t, n);
}
template<typename World, typename T, size_t aSize>
void recv( World& w, int dest, int tag, T (*arr1)[aSize], size_t n = 1) {
  world.recv(dest, tag, &(*arr)[0], n*aSize);
}
template<typename World, typename T, size_t aSize, size_t bSize>
void recv( World& w, int dest, int tag, T (*arr2)[aSize][bSize], size_t n = 1) {
  world.recv(dest, tag, &(*arr)[0][0], n*aSize*bSize);
}

对于一维和二维数组,上面的代码会计算出你真正想要发送多少个 T 副本,而不是你必须手动维护它。

它甚至适用于切片,例如 &amp;A[low_bound], upper_bound-lower_bound

您可能要小心的一件事是吹过阵列的末端。您的 C 代码很容易超出数组的末尾,但那里没有任何重要的东西,所以它幸存了下来。在 C++ 代码中,你可以在那里有一个对象,然后你会死而不是生存。

另一种方法可能是编写一个同时接受切片上限和下限的函数,如下所示:

template<typename World, typename T, size_t N>
void isend_slice( World& w, int dest, int tag, T const (&t)[N], size_t start=0, size_t end=N ) {
  Assert( end <= N && start < end );
  isend(world, dest, tag, &(t[start]), end-start);
}
template<typename World, typename T, size_t N>
void recv_slice( World& w, int dest, int tag, T (&t)[N], size_t start=0, size_t end=N ) {
  Assert( end <= N && start < end );
  recv(world, dest, tag, &(t[start]), end-start);
}

在这种情况下,你直接传递一个数组,然后说出你想从哪里开始和结束阅读。好处是我检查了数组是否真的有数据要发送,或者数据到达的空间。

(这两个函数依赖于上面的函数)

在分布式情况下,您希望为您的 Asserts 生成一个描述性的日志记录机制。

以下是上述代码的示例用法:

int array[10];
int array2[10][10];
isend(world, dest, tag+0, &int(7)); // tag is an int
isend(world, dest, tag+1, &array); // tag+1 is a 10 int array
isend(world, dest, tag+2, &array2); // tag+2 is a 100 int array
isend(world, dest, tag+1, &(array2[5])); // tag+1 is a 10 int array
isend_slice(world, tag+3, 0, array2, 7, 11); // asserts, but its a 40 int array

recv 也是如此。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-21
    • 2019-12-27
    • 2018-11-09
    • 2016-05-07
    • 2020-09-18
    • 2017-08-28
    • 2011-08-19
    相关资源
    最近更新 更多