繁体   English   中英

如何MPI_SEND和MPI_RECV

[英]How to MPI_SEND and MPI_RECV

我有一个输入文件.txt,其中有序列:

NAMEOFSEQUENCE1/SEQUENCE1
NAMEOFSEQUENCE2/SEQUENCE2
NAMEOFSEQUENCE3/SEQUENCE3

我做了一个结构:

typedef struct lane{
  char *name;
  char *sequence;
}lane;

并写了这段代码:

int i=0;
lane* toSend    = malloc(sizeof(*toSend)*3);
while (fgets(line,strlen(line),fileinput) != NULL){
            //GETTING NAME AND SEQUENCE, LINE PER LINE
            char *tempName = malloc(strlen(line)-strlen(strstr(line,"\\"))+1);
            strncpy(tempName,line,strlen(line)-strlen(strstr(line,"\\")));
            tempName[strlen(line)-strlen(strstr(line,"\\"))] = '\0';
            char *tempSequence = malloc(strlen(strstr(line,"\\")));
            strncpy(tempSequence,strstr(line,"\\")+1,strlen(strstr(line,"\\")));
            tempSequence[strlen(strstr(line,"\\"))-1] = '\0';

            //FILLING TOSEND
            toSend[i].name      = malloc(strlen(line)-strlen(strstr(line,"\\"))+1);
            toSend[i].sequence  = malloc(strlen(strstr(line,"\\")));
            howmuchbyte += strlen(line)+1;
            strcpy(toSend[i].name,tempName);
            strcpy(toSend[i].sequence,tempSequence);
            i++;
}

我一次输入文件的“line”变量一行,并在tempName中输入每个序列的NAMEOFSEQUENCEX,并在tempSequence中输入SEQUENCEX。

一切正常。 如果我打印“发送”矢量我得到正确的价值! 所以我写了这个:

MPI_Send(toSend, 3, MPI_BYTE, 1, tag, MPI_COMM_WORLD);

所以我从等级0的过程发送到等级1的过程(我有2个过程)。 我把3作为计数参数,因为我在数组中有3个元素。

排名为1的过程执行此操作:

lane* received  = malloc(sizeof(*received)*3);
MPI_Recv(received, 3, MPI_BYTE, 0, tag, MPI_COMM_WORLD, &status);

如果我在排名为1的过程中执行此操作:

printf("%s",received[0].name);

我得到了分段错误。 我错了什么?

您不能只在MPI通道上发送原始指针。 好吧,你可以,但是从一些其他进程接收指针的进程将不会在指针引用的内存位置(在它们自己的内存空间中)具有相同的数据。

如果要通过MPI发送可变大小的数组(例如字符串),则需要首先测试数组的大小,并在接收端分配适当大小的数组。

有关更多信息: 如何使用MPI发送和接收字符串

如果您的字符串具有固定的最大长度,这可能会起作用,例如

typedef struct lane{
   char name[NAME_MAX];
   char sequence[SEQ_MAX];
 }lane;

在这种情况下,您只需定义一个新的MPI结构化数据类型,并在发送和接收操作中使用它:

int blens[2] = { NAME_MAX, SEQ_MAX };
int disps[2] = { offsetof(lane, name), offsetof(lane, sequence) };
int oldtypes[2] = { MPI_CHAR, MPI_CHAR };
MPI_Datatype type_lane;

MPI_Type_create_struct(2, blens, disps, oldtypes, &type_lane);
MPI_Type_commit(&type_lane);

lane aLane[2];

if (rank == 0)
{
   strncpy(aLane[0].name, NAME_MAX, "foo1");
   strncpy(aLane[0].sequence, SEQ_MAX, "bar");

   strncpy(aLane[1].name, NAME_MAX, "foo2");
   strncpy(aLane[1].sequence, SEQ_MAX, "baz");

   MPI_Send(aLane, 2, type_lane, 1, tag, MPI_COMM_WORLD);
}
else if (rank == 1)
{
   MPI_Recv(aLane, 2, type_lane, 0, tag, MPI_COMM_WORLD, &status);
}

如果您的字符串长度变化很大,那么您应该在发送之前序列化每个结构。 我想到的最简单的事情就是连接所有名称/序列对,用NUL分隔:

int total_length = 0;

for (i = 0; i < num_to_send; i++)
   total_length += strlen(toSend[i].name) + strlen(toSend[i].sequence) + 2;

char *bigstr = malloc(total_length);
char *cur = bigstr;

for (i = 0; i < num_to_send; i++)
{
   strcpy(cur, toSend[i].name);
   cur += strlen(toSend[i].name) + 1;
   strcpy(cur, toSend[i].sequence);
   cur += strlen(toSend[i].sequence) + 1;
}

现在bigstr的内容如下:

toSend[0].name \0 toSend[0].sequence \0 toSend[1].name \0 toSend[1].sequence \0 ....

发件人现在可以发送字符串并处理它:

MPI_Send(bigstr, total_length, MPI_CHAR, 1, tag, MPI_COMM_WORLD);

接收方必须准备好接收未知大小的消息。 这可以通过首先调用MPI_Probe然后调用MPI_Recv来实现:

MPI_Status;

MPI_Probe(1, tag, MPI_COMM_WORLD, &status);
MPI_Get_count(&status, MPI_CHAR, &total_length);

char *bigstr = malloc(total_length);
MPI_Recv(bigstr, total_length, MPI_CHAR, 1, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

现在,您需要将大字符串反序列化为元组集合。 一种方法是首先走它并计算NUL的数量并将它们除以2。 然后再次走动并将每个项目复制到相应的位置:

int num_structs = 0;

for (i = 0; i < total_length; i++)
   if (bigstr[i] == '\0') num_structs++;
num_structs /= 2;

lane *lanes = malloc(num_structs * sizeof(lane));
char *cur = bigstr;

for (i = 0; i < num_structs; i++)
{
   lanes[i].name = strdup(cur);
   cur += strlen(cur);
   lanes[i].sequence = strdup(cur);
   cur += strlen(cur);
}

另一种可能的解决方案是使用MPI_PackMPI_Unpack

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM