使用MPI_Gather openmpi c收集字符串

我想为每个进程生成一个字符串,然后收集所有内容。 但是每个进程中创建的字符串都是通过附加int和chars创建的。

我仍然无法正确收集所有东西。 我可以逐个打印所有部分字符串,但是如果我尝试打印rcv_string,我只得到一个部分字符串或者可能是分段错误。

我已经尝试在memset的字符串末尾添加零,动态和静态地为字符串保留内存,但是我找不到方法。

如果有人知道如何对字符串进行初始化并正确地进行聚集以实现目标,那将会很棒。

int main(int argc, char *argv[]) { int rank; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); char *string; // ???????????? char *rcv_string; // ???????????? if (rank == 0) { sprintf(string+strlen(string), "%dr%dg%db%dl\n",255,255,255,0); } else if (rank == 1) { sprintf(string+strlen(string), "%dr%dg%db%dl\n",255,255,255,0); } else if (rank == 2) { sprintf(string+strlen(string), "%dr%dg%db%dl\n",255,255,255,0); } else if (rank == 3) { sprintf(string+strlen(string), "%dr%dg%db%dl\n",255,255,255,0); } else if (rank == 4) { sprintf(string+strlen(string), "%dr%dg%db%dl\n",255,255,255,0); } else if (rank == 5) { sprintf(string+strlen(string), "%dr%dg%db%dl\n",255,255,255,0); } MPI_Gather(string,???,MPI_CHAR,rcv_string,???,MPI_CHAR,0,MPI_COMM_WORLD); if (rank == 0) { printf("%s",rcv_string); } MPI_Finalize(); return 0; } 

我设法重现了只打印一个部分字符串的错误行为。

它与您对sprintf的使用有关。

C如何处理char数组?

在C中使用数组时,必须先为其分配内存。 动态或静态,没关系。 假设您为10个char分配了足够的内存。

 char my_string[10]; 

没有初始化它,它包含无意义的字符。

让我们假装my_string包含"qwertyuiop"

假设您要使用字符串foo填充my_string 。 你使用sprintf

 sprintf(my_string, "foo"); 

C如何用3个字符填充10个插槽?

它用3个字符填充前3个插槽。 然后,它用“字符串结束”字符填充第4个插槽。 这用'\0'表示,当它通过编译器时转换为“字符串结束”字符。

因此,在您的命令之后, my_string包含"foo\0tyuiop" 。 如果你打印出my_string ,C知道不会在\0之后打印出无意义的字符。

这与MPI_Gather什么关系?

MPI_Gather从不同进程收集数组,并将它们全部放入一个进程的一个数组中。

如果你在进程0和"bar\0ghjkl;"上有"foo\0tyuiop" "bar\0ghjkl;" 在进程1中,它们合并为"foo\0tyuiopbar\0ghjkl;"

如您所见,进程1中的数组出现在进程0的“行尾”字符之后.C将处理进程1中的所有字符视为无意义。

一个不完整的解决方案

不要试图一次打印所有rcv_string ,而是确认散布着“字符串结束”字符。 然后,根据它来自的过程,打印出具有不同“字符串开头”位置的字符串。

 #include  #include  #include  #include  int main(int argc, char *argv[]) { int rank, size; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); int part_str_len = 18; char *my_string; char *rcv_string; if ((my_string = malloc(part_str_len*sizeof(char))) == NULL){ MPI_Abort(MPI_COMM_WORLD,1); } if ((rcv_string = malloc(part_str_len*size*sizeof(char))) == NULL){ MPI_Abort(MPI_COMM_WORLD,1); } sprintf(my_string, "%dr%dg%db%dl\n",255,255,255,0); MPI_Gather(my_string,18,MPI_CHAR,rcv_string,18,MPI_CHAR,0,MPI_COMM_WORLD); if (rank == 0) { printf("%s",rcv_string); } char *cat_string; if ((cat_string = malloc(part_str_len*size*sizeof(char))) == NULL){ MPI_Abort(MPI_COMM_WORLD,1); } if (rank == 0){ int i; sprintf(cat_string, "%s", rcv_string); for (i = 1; i < size; i++){ strcat(cat_string, &rcv_string[part_str_len*i]); } } if (rank == 0) { printf("%s",cat_string); } free(my_string); free(rcv_string); free(cat_string); MPI_Finalize(); return 0; } 

请尝试以下方法:

 #define MAX_STR_LEN 100 int main(int argc, char *argv[]) { int rank, size; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); char string[MAX_STR_LEN] = "some string"; char *rcv_string = NULL; if (rank == 0) { // Only the master needs to allocate the memory // for the result string which needs to be large // enough to contain the input strings from `size` // peers. rcv_string = malloc(MAX_STR_LEN * size); } ...same code... MPI_Gather(string, strlen(string), MPI_CHAR, rcv_string, MAX_STR_LEN, MPI_CHAR, 0, MPI_COMM_WORLD); if (rank == 0) { printf("%s",rcv_string); free(rcv_string); } MPI_Finalize(); return 0; } 

使用mpirun -n 5 ./a.out运行此代码会产生以下结果:

 some string255r255g255b0l some string255r255g255b0l some string255r255g255b0l some string255r255g255b0l some string255r255g255b0l 

确保定义MAX_STR_LEN以便足以满足您的要求。 如果值增大到大,您可能需要考虑堆分配(即malloc )。