【问题标题】:How to MPI_SEND and MPI_RECV如何 MPI_SEND 和 MPI_RECV
【发布时间】:2014-04-17 09:29:54
【问题描述】:

我有一个输入文件 .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”变量中,并将每个序列的NAMEOFSEQUENCEX 放入tempName,并将SEQUENCEX 放入tempSequence。

此时一切正常。如果我打印“toSend”向量,我会得到正确的值! 所以我写了这个:

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

我遇到了分段错误。我怎么了?

【问题讨论】:

  • sizeof(lane) * 3 ?而不仅仅是 3 个?
  • 刚试过。另一个分段错误

标签: c openmpi


【解决方案1】:

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

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

欲了解更多信息:How to send and receive string using MPI

【讨论】:

    【解决方案2】:

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

    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

    【讨论】:

      猜你喜欢
      • 2011-11-11
      • 2011-01-24
      • 2017-10-25
      • 2016-04-22
      • 2021-05-07
      • 2015-05-14
      • 1970-01-01
      • 1970-01-01
      • 2016-09-09
      相关资源
      最近更新 更多