简体   繁体   English

如何MPI_SEND和MPI_RECV

[英]How to MPI_SEND and MPI_RECV

i have an this input file .txt where there are sequences: 我有一个输入文件.txt,其中有序列:

NAMEOFSEQUENCE1/SEQUENCE1
NAMEOFSEQUENCE2/SEQUENCE2
NAMEOFSEQUENCE3/SEQUENCE3

I done a struct: 我做了一个结构:

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

and wrote this code: 并写了这段代码:

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++;
}

I put in "line" variable one line of the file at a time and put in tempName the NAMEOFSEQUENCEX of each sequence and put in tempSequence the SEQUENCEX. 我一次输入文件的“line”变量一行,并在tempName中输入每个序列的NAMEOFSEQUENCEX,并在tempSequence中输入SEQUENCEX。

At this point all is working. 一切正常。 If i Print the "toSend" vector i get the right value! 如果我打印“发送”矢量我得到正确的价值! So i wrote this: 所以我写了这个:

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

so i send from process with rank 0 to process with rank 1 (i have 2 process). 所以我从等级0的过程发送到等级1的过程(我有2个过程)。 I put 3 as count parameter because i have 3 elements in the array. 我把3作为计数参数,因为我在数组中有3个元素。

The process with rank 1 do this: 排名为1的过程执行此操作:

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

If i do this on process with rank 1: 如果我在排名为1的过程中执行此操作:

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

i get a segmentation fault. 我得到了分段错误。 What do i wrong? 我错了什么?

You can't just send raw pointers across an MPI channel. 您不能只在MPI通道上发送原始指针。 Well, you can, but the process that receives a pointer from some other process won't have the same data at the memory location (in their own memory space) referred to by the pointer. 好吧,你可以,但是从一些其他进程接收指针的进程将不会在指针引用的内存位置(在它们自己的内存空间中)具有相同的数据。

If you want to send a variably-sized array (such as a string) through MPI, you'll need to test for the size of the array first, and allocate an appropriately sized array on the receiving end. 如果要通过MPI发送可变大小的数组(例如字符串),则需要首先测试数组的大小,并在接收端分配适当大小的数组。

For more info: How to send and receive string using MPI 有关更多信息: 如何使用MPI发送和接收字符串

This could work if your strings are of fixed maximum length, eg 如果您的字符串具有固定的最大长度,这可能会起作用,例如

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

In that case you can simply define a new MPI structured datatype and use it in both send and receive operations: 在这种情况下,您只需定义一个新的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);
}

If your strings are of strongly varying lengths, then you should serialize each structure before sending it. 如果您的字符串长度变化很大,那么您应该在发送之前序列化每个结构。 The most simple thing that comes to my mind is to just concatenate all name/sequence pairs, separated by a NUL: 我想到的最简单的事情就是连接所有名称/序列对,用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;
}

Now the content of bigstr is as follows: 现在bigstr的内容如下:

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

The sender can now send the string and dispose it: 发件人现在可以发送字符串并处理它:

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

The receiver has to be prepared to receive a message of unknown size. 接收方必须准备好接收未知大小的消息。 That can be achieved by first calling MPI_Probe and then MPI_Recv : 这可以通过首先调用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);

Now comes the part where you have to deserialise the big string into a collection of tuples. 现在,您需要将大字符串反序列化为元组集合。 One way to do it is to first walk it and count the number of NULs and divide them by two. 一种方法是首先走它并计算NUL的数量并将它们除以2。 Then walk it again and copy each item to the corresponding location: 然后再次走动并将每个项目复制到相应的位置:

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);
}

Another possible solution would be to utilise MPI_Pack and MPI_Unpack instead. 另一种可能的解决方案是使用MPI_PackMPI_Unpack

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

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