在MPI进程之间传递可变长度的结构体

6

我需要使用 MPI_Gatherv() 来收集一些整数/字符串对。假设每对键值对的格式如下:

struct Pair {
  int x;
  unsigned s_len;
  char s[1]; // variable-length string of s_len chars
};

如何为Pair定义合适的MPI数据类型?

请使用char s[0];来定义可变长度数组,而不是char s[1]; - kennytm
@KennyTM,s[0]会出现“警告C4200:在结构/联合中使用了非标准扩展:零大小数组”的提示。 - Constantin
啊,MSVC。C99 在 gcc 中得到了很好的支持,但在 MSVC 中却没有。 - kennytm
@KennyTM,嗯,我仍然在想s[0]更正确的意义是什么?如果我知道我的字符串永远不会为空,那么s[0]仍然更正确吗? - Constantin
3个回答

5
简而言之,将一个可变大小的消息发送并接收到一个完美大小的缓冲区在理论上是不可能的。你需要先发送一条包含每个字符串大小的第一条消息,然后再发送包含字符串本身的第二条消息,或者将元数据编码到有效载荷中并使用静态接收缓冲区。
如果你必须只发送一条消息,那么我建议放弃为Pair定义数据类型:相反,我会创建整个有效载荷的数据类型,并将所有数据转储到一个连续的、无类型的包中。然后在接收端,你可以遍历它,分配每个字符串所需的确切空间并填充它。让我设计一个ASCII图来说明。这将是你的有效载荷: |..x1..|..s_len1..|....string1....|..x2..|..s_len2..|.string2.|..x3..|..s_len3..|.......string3.......|
你将整个内容作为一个单元发送(例如一个MPI_BYTE数组),然后接收方将解压缩它,类似于以下方式:
while (buffer is not empty)
{
    read x;
    read s_len;
    allocate s_len characters;
    move s_len characters from buffer to allocated space;
}

请注意,此解决方案仅在发送和接收系统的整数和字符的数据表示相同时才有效。

将所有内容打包到连续的缓冲区中是我最终确定的方案。需要注意的一点是,我不得不使用额外的MPI_Gather()函数来收集每个进程的有效载荷大小。这些有效载荷大小用于计算接收缓冲区的大小和位移向量(http://www.mpi-forum.org/docs/mpi-11-html/node70.html)。 - Constantin

3
我认为你无法通过MPI完全实现你想要的功能。我是一名Fortran程序员,如果我对C的理解有些模糊,请见谅。你想传递一个数据结构,其中包含1个整数和1个字符串(通过传递字符串中第一个字符的位置进行传递)从一个进程传递到另一个进程?我认为你将不得不传递一个固定长度的字符串,因此它必须与你想要传递的任何字符串一样长。用于收集这些字符串的接收区域必须足够大,以接收所有字符串及其长度。
你可能需要为你的结构声明一个新的MPI数据类型;然后你可以收集这些数据,并且由于收集的数据包括字符串的长度,在接收方恢复字符串的有用部分。
我不确定这一点,但我从未遇到过真正可变的消息长度,就像你似乎想要使用的那样,这似乎不符合MPI的风格。但它可能是MPI的最新版本中实现的某些东西,我只是从未偶然发现过,尽管在线文档看起来并非如此。

我希望避免使用固定长度缓冲区浪费空间。另一个可能要避免的选项是用两个单独的数组表示len/chars对的数组:一个是长度,一个是字符。无论如何,还是谢谢。 - Constantin
马克,我已经有一段时间没有使用MPI了,但我相当确定你在这里是正确的。至少对于2005年左右的MPI来说是如此。 - Paul Nathan

1

MPI实现不会检查或解释消息的实际内容。只要您知道数据结构的大小,就可以用一些char或int表示该大小。MPI实现将不知道或关心数据的实际内部细节。

有一些注意事项...发送方和接收方都需要就消息内容的解释达成一致,并且您在发送和接收端提供的缓冲区需要适合某些可定义的char或int数量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接