使用 MPI_Gather openmpi c 收集字符串
Gathering strings with MPI_Gather openmpi c
我想为每个进程生成一个字符串,然后收集所有内容。但是在每个进程中创建的字符串都是通过附加 int 和 char 创建的。
我仍然无法正确收集所有内容。我可以一个一个地打印所有部分字符串,但是如果我尝试打印 rcv_string,我只会得到一个部分字符串或者可能是一个分段错误。
我试过用 memset 在字符串末尾置零,为字符串动态和静态保留内存,...但我找不到方法。
如果有人知道如何初始化字符串并正确地进行收集以实现 objective,那就太好了。
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;
}
尝试以下操作:
#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
)。
我设法重现了只打印了一个部分字符串的错误行为。
这与您使用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 个槽位。然后,它用 "end of string" 字符填充第 4 个槽。这由 '[=21=]'
表示,它在通过编译器时被转换为 "end of string" 字符。
因此,在您的命令之后,my_string
包含 "foo[=23=]tyuiop"
。如果打印出my_string
,C就知道不要打印出[=25=]
.
后面的无意义字符
这与 MPI_Gather
有什么关系?
MPI_Gather
收集不同进程的数组,在一个进程上全部放到一个数组中
如果您在进程 0 上有 "foo[=23=]tyuiop"
并且在进程 1 上有 "bar[=29=]ghjkl;"
,它们将合并为 "foo[=30=]tyuiopbar[=30=]ghjkl;"
。
如您所见,进程 1 的数组出现在进程 0 的 "end of line" 字符之后。C 会将进程 1 的所有字符视为无意义。
一个不完整的解决方案
与其尝试一次打印所有 rcv_string
,不如承认有 "end of string" 个字符分散在各处。然后,根据它来自的过程,打印出"start of string"位置不同的字符串。
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}
我想为每个进程生成一个字符串,然后收集所有内容。但是在每个进程中创建的字符串都是通过附加 int 和 char 创建的。
我仍然无法正确收集所有内容。我可以一个一个地打印所有部分字符串,但是如果我尝试打印 rcv_string,我只会得到一个部分字符串或者可能是一个分段错误。
我试过用 memset 在字符串末尾置零,为字符串动态和静态保留内存,...但我找不到方法。
如果有人知道如何初始化字符串并正确地进行收集以实现 objective,那就太好了。
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;
}
尝试以下操作:
#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
)。
我设法重现了只打印了一个部分字符串的错误行为。
这与您使用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 个槽位。然后,它用 "end of string" 字符填充第 4 个槽。这由 '[=21=]'
表示,它在通过编译器时被转换为 "end of string" 字符。
因此,在您的命令之后,my_string
包含 "foo[=23=]tyuiop"
。如果打印出my_string
,C就知道不要打印出[=25=]
.
这与 MPI_Gather
有什么关系?
MPI_Gather
收集不同进程的数组,在一个进程上全部放到一个数组中
如果您在进程 0 上有 "foo[=23=]tyuiop"
并且在进程 1 上有 "bar[=29=]ghjkl;"
,它们将合并为 "foo[=30=]tyuiopbar[=30=]ghjkl;"
。
如您所见,进程 1 的数组出现在进程 0 的 "end of line" 字符之后。C 会将进程 1 的所有字符视为无意义。
一个不完整的解决方案
与其尝试一次打印所有 rcv_string
,不如承认有 "end of string" 个字符分散在各处。然后,根据它来自的过程,打印出"start of string"位置不同的字符串。
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}