[英]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_Pack
和MPI_Unpack
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.