C-MPI 发送创建的带有字符数组的 typedef 结构

Posted

技术标签:

【中文标题】C-MPI 发送创建的带有字符数组的 typedef 结构【英文标题】:C-MPI Send created typedef struct with array of chars 【发布时间】:2016-05-08 17:24:39 【问题描述】:

您好,我有一个包含这种数据行的文件:

AsfAGHM5om  00000000000000000000000000000000  0000222200002222000022220000222200002222000000001111

我想读取此类数据并使用 C 和 MPI 将它们发送过来。所以我达到了以下C代码:

    #include <mpi.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stddef.h> // used for offsetof
    typedef struct tuple_str
        char *key;
        char *index;
        char *value;
     tuple;

    int main(int argc, char** argv) 

        // Initialize the MPI environment
        MPI_Init(&argc, &argv);

        // Initialize file pointer
        FILE *fp = fopen("tuples","r");

        // define original structure that stores file and temp used by each process
        tuple A[10000],B[10000];
        // mpi structure name
        MPI_Datatype mpi_tuples_str;
        // number of structure members
        const int nitems = 3;
        // array of structure member sizes
        int blocklengths[3];
        blocklengths[0] = sizeof(A->key);
        blocklengths[1] = sizeof(A->index);
        blocklengths[2] = sizeof(A->value);
        // structure member types
        MPI_Datatype types[3] = MPI_CHAR,MPI_CHAR,MPI_CHAR;
        // status
        MPI_Status status;
        // offset of structure members
        MPI_Aint offsets[3];
        offsets[0] = offsetof(tuple,key);
        offsets[1] = offsetof(tuple,index);
        offsets[2] = offsetof(tuple,value);

        // create mpi struct
        MPI_Type_create_struct(nitems,blocklengths, offsets, types, &mpi_tuples_str);
        MPI_Type_commit(&mpi_tuples_str);

        // Get the number of processes
        int size;
        MPI_Comm_size(MPI_COMM_WORLD, &size);

        // Get the rank of the process
        int my_rank;
        MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

        int index = 0;
        int i;
        int local_A_size = (10000%size == 0) ? 10000/size : 0;

        if ( my_rank == 0)
          char text[10000];
          char *p;
          p=strtok(NULL," ");
          // node0 reads file form hard drive and saves file to struct
          while( fgets(text,10000,fp)!=NULL)
            p = strtok (text," ");
            char *temp[3];
            temp[0]=p;
            A[index].key=temp[0];
            p = strtok (NULL, " ");
            temp[1] = p;
            A[index].index=temp[1];
            p = strtok (NULL, " ");
            temp[2] = p;
            A[index].value=temp[2];
            // printf("%s ",A[index].key);
            // printf("%s ",A[index].index);
            // printf("%s\n",A[index].value);
            index++;
          
          fclose(fp);
        

        if ( local_A_size != 0)
          if (my_rank == 0) 
            printf("File saved to memory of process %d!\n",my_rank);
            printf("Process %d sending struct data to others...\n",my_rank);
          

          // send struct to all processes
          MPI_Scatter(&A,local_A_size,mpi_tuples_str,B,local_A_size,mpi_tuples_str,0,MPI_COMM_WORLD);
          // MPI_Bcast(&A,index,mpi_tuples_str,0,MPI_COMM_WORLD);

          for(i=0;i<=local_A_size;i++)
           printf("I'm process %d and my result is: %s\n",my_rank,B[i].key);

          if (my_rank == 0) printf("Data sent from process %d to others...\n",my_rank);
        
        else
        
          if (my_rank == 0) printf("Number of processes must be an exact divisor of %d, %d in not %ds divisor\n",index,size,index);
        
          // free memory used by mpi_tuples_str
          MPI_Type_free(&mpi_tuples_str);
          // Finalize
          MPI_Finalize();
        return 0;
    

因此,据我所知,这里的问题是首先创建和分配我的结构的内存,然后打包和发送它。 如您所见,我尝试了MPI_ScatterMPI_Bcast,但没有一个对我有帮助。 结果是,正如预期的那样,读取文件的进程 0 有数据,但所有其他进程都没有。我也收到了这个奇怪的信息

=   BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
=   EXIT CODE: 11
=   CLEANING UP REMAINING PROCESSES
=   YOU CAN IGNORE THE BELOW CLEANUP MESSAGES

如果有人能启发我,我将不胜感激!

好的,我已将代码更改为以下内容:

`#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h> // used for offsetof
typedef struct tuple_str
    char key[10];
    char index[12];
    char value[52];
 tuple;

int main(int argc, char** argv) 

    // Initialize the MPI environment
    MPI_Init(NULL, NULL);

    // Initialize file pointer
    FILE *fp = fopen("tuples_mini","r");

    // define original structure that stores file and temp used by each process
    tuple A[10000],B[10000];
    // mpi structure name
    MPI_Datatype mpi_tuples_str;
    // number of structure members
    const int nitems = 3;
    // array of structure member sizes
    int blocklengths[3];
    blocklengths[0] = sizeof(10);
    blocklengths[1] = sizeof(12);
    blocklengths[2] = sizeof(52);
    // structure member types
    MPI_Datatype types[3] = MPI_CHAR,MPI_CHAR,MPI_CHAR;
    // status
    MPI_Status status;
    // offset of structure members
    MPI_Aint offsets[3];
    offsets[0] = offsetof(tuple,key);
    offsets[1] = offsetof(tuple,index);
    offsets[2] = offsetof(tuple,value);

    // create mpi struct
    MPI_Type_create_struct(nitems,blocklengths, offsets, types, &mpi_tuples_str);
    MPI_Type_commit(&mpi_tuples_str);

    // Get the number of processes
    int size;
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    // Get the rank of the process
    int my_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    int index = 0;
    int i;
    int local_A_size = (10000%size == 0) ? 10000/size : 0;
    char *tmp[10000],*b[10000];

    if ( my_rank == 0)
      char text[10000];
      char *p;
      p=strtok(NULL," ");
      // node0 reads file form hard drive and saves file to struct
      while( fgets(text,10000,fp)!=NULL)
        p = strtok (text," ");
        char *temp[3];
        temp[0]=p;
        strcpy(A[index].key,temp[0]);
        p = strtok (NULL, " ");
        temp[1] = p;
        strcpy(A[index].index,temp[1]);
        p = strtok (NULL, " ");
        temp[2] = p;
        strcpy(A[index].value,temp[2]);
        printf("%s ",A[index].key);
        printf("%s ",A[index].index);
        printf("%s\n",A[index].value);
        index++;
      
      fclose(fp);
    

    if ( local_A_size != 0)
      if (my_rank == 0) 
        printf("File saved to memory of process %d!\n",my_rank);
        printf("Process %d sending struct data to others...\n",my_rank);
      

      // send struct to all processes
      MPI_Scatter(&A,index,mpi_tuples_str,B,index,mpi_tuples_str,0,MPI_COMM_WORLD);
      // MPI_Bcast(&tmp,index,MPI_CHAR,0,MPI_COMM_WORLD);

      for(i=0;i<=local_A_size;i++)
          // MPI_Recv(&tmp,index,MPI_CHAR,0,10,MPI_COMM_WORLD,&status);
          printf("I'm process %d and my result is: %s\n",my_rank,B[i].key);
      

      if (my_rank == 0) printf("Data sent from process %d to others...\n",my_rank);
    
    else
    
      if (my_rank == 0) printf("Number of processes must be an exact divisor of %d, %d in not %ds divisor\n",index,size,index);
    
      // free memory used by mpi_tuples_str
      MPI_Type_free(&mpi_tuples_str);
      // Finalize
      MPI_Finalize();
    return 0;
`

但这导致我出现新错误:

    ==============================================================================    =====
=   BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
=   EXIT CODE: 6
=   CLEANING UP REMAINING PROCESSES
=   YOU CAN IGNORE THE BELOW CLEANUP MESSAGES
==============================================================================    =====
YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Aborted (signal 6)
This typically refers to a problem with your application.
Please see the FAQ page for debugging suggestions

在最后的建议之后!

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h> // used for offsetof
typedef struct tuple_str
    char key[10];
    char index[12];
    char value[52];
 tuple;
int main(int argc, char** argv) 
  // Initialize the MPI environment
  MPI_Init(NULL, NULL);

  // Initialize file pointer
  FILE *fp = fopen("tuples_mini","r");

  // define original structure that stores file and temp used by each process
 tuple A[10000],B[10000];
 // mpi structure name
 MPI_Datatype mpi_tuples_str;
 // number of structure members
 const int nitems = 3;
 // array of structure member sizes
 int blocklengths[3];
 blocklengths[0] = 11;
 blocklengths[1] = 33;
 blocklengths[2] = 53;
 // structure member types
 MPI_Datatype types[3] = MPI_CHAR,MPI_CHAR,MPI_CHAR;
 // status
 MPI_Status status;
 // offset of structure members
 MPI_Aint offsets[3];
 offsets[0] = offsetof(tuple,key);
 offsets[1] = offsetof(tuple,index);
 offsets[2] = offsetof(tuple,value);

 // create mpi struct
 MPI_Type_create_struct(nitems,blocklengths, offsets, types, &mpi_tuples_str);
 MPI_Type_commit(&mpi_tuples_str);

 // Get the number of processes
 int size;
 MPI_Comm_size(MPI_COMM_WORLD, &size);

// Get the rank of the process
int my_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

int index = 0;
int i;
int local_A_size = (10000%size == 0) ? 10000/size : 0;
char *tmp[10000],*b[10000];

if ( my_rank == 0)
  char text[10000];
  char *p;
  // p=strtok(NULL," ");
  // node0 reads file form hard drive and saves file to struct
  while( fgets(text,10000,fp) != NULL && fp != NULL)
    p = strtok (text," ");
    char *temp[3];
    temp[0]=p;
    strcpy(A[index].key,temp[0]);
    p = strtok (NULL, " ");
    temp[1] = p;
    strcpy(A[index].index,temp[1]);
    p = strtok (NULL, " ");
    temp[2] = p;
    strcpy(A[index].value,temp[2]);
    printf("%s ",A[index].key);
    printf("%s ",A[index].index);
    printf("%s\n",A[index].value);
    tmp[index] = temp[0];
    // printf("%s\n",tmp[index]);
    index++;
  
  fclose(fp);


if ( local_A_size != 0)
  if (my_rank == 0) 
    printf("File saved to memory of process %d!\n",my_rank);
    printf("Process %d sending struct data to others...\n",my_rank);
    // MPI_Send(&A,index,mpi_tuples_str,0,10,MPI_COMM_WORLD);
  

  // send struct to all processes
     MPI_Scatter(&A,index,mpi_tuples_str,B,index,mpi_tuples_str,0,MPI_COMM_WORLD);
  // MPI_Bcast(&tmp,index,MPI_CHAR,0,MPI_COMM_WORLD);
  // MPI_Bcast(&A,index,mpi_tuples_str,0,MPI_COMM_WORLD);

  for(i=0;i<=local_A_size;i++)
      // MPI_Recv(&tmp,index,MPI_CHAR,0,10,MPI_COMM_WORLD,&status);
      // MPI_Recv(&A,index,mpi_tuples_str,0,10,MPI_COMM_WORLD,&status);
      printf("I'm process %d and my result is: %s\n",my_rank,B[i].key);
  

  if (my_rank == 0) printf("Data sent from process %d to others...\n",my_rank);

else

  if (my_rank == 0) printf("Number of processes must be an exact divisor of %d, %d in not %ds divisor\n",index,size,index);

  // free memory used by mpi_tuples_str
  MPI_Type_free(&mpi_tuples_str);
  // Finalize
  MPI_Finalize();
return 0;

【问题讨论】:

sizeof (A-&gt;key) 等不返回调用MPI_Type_create_struct所需的最大字符串长度,见here 好吧,我不会不同意,但我怎样才能获得这些字符数组指针的大小? 我认为,您应该在结构中为keyindexvalue 使用固定大小的数组。当然,您必须在标记化中使用 strcnpy 并检查字符串长度。 我猜blocklengths[0] = sizeof(10); 应该是blocklengths[0] = 10;,下面两行也是如此。 调用函数时:strtok(),始终检查(!=NULL)返回值以确保操作成功。 【参考方案1】:

我在贴出的代码中应用了所有关于问题的cmets,结果如下:

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h> // used for offsetof

typedef struct tuple_str

    char key[11];
    char index[33];
    char value[53];
 tuple;

int main( void )


    // Initialize the MPI environment
    MPI_Init( NULL, NULL );

    // Initialize file pointer
    FILE *fp = NULL;
    if( NULL == ( fp = fopen( "tuples_mini" ,"r" ) ) )
    
        perror( "fopen for read of truples_mini failed" );
        exit( EXIT_FAILURE );
    

    // implied else, fopen successful

    // define original structure that stores file and temp used by each process
    tuple A[10000];
    tuple B[10000];

    // mpi structure name
    MPI_Datatype mpi_tuples_str;

    // number of structure members
    const int nitems = 3;

    // array of structure member sizes
    int blocklengths[3];
    blocklengths[0] = 11;
    blocklengths[1] = 33;
    blocklengths[2] = 53;

    // structure member types
    MPI_Datatype types[3] =  MPI_CHAR, MPI_CHAR, MPI_CHAR ;

    // status
    //MPI_Status status;

    // offset of structure members
    MPI_Aint offsets[3];
    offsets[0] = offsetof( tuple,key);
    offsets[1] = offsetof( tuple,index);
    offsets[2] = offsetof( tuple,value);

    // create mpi struct
    MPI_Type_create_struct( nitems, blocklengths, offsets, types, &mpi_tuples_str);
    MPI_Type_commit( &mpi_tuples_str);

    // Get the number of processes
    int size;
    MPI_Comm_size( MPI_COMM_WORLD, &size);

    // Get the rank of the process
    int my_rank;
    MPI_Comm_rank( MPI_COMM_WORLD, &my_rank);

    int index = 0;
    int i;
    int local_A_size = (10000%size == 0) ? 10000/size : 0;
    //char *tmp[10000];
    //char *b[10000];

    if ( my_rank == 0)
    
      char text[10000];
      char *p;
      //p=strtok(NULL," ");

      // node0 reads file from hard drive and saves file to struct
      while( fgets( text, sizeof text, fp ) )
      
        p = strtok (text," ");
        char *temp[3];
        temp[0]=p;
        strcpy( A[index].key,temp[0]);

        p = strtok (NULL, " ");
        temp[1] = p;
        strcpy( A[index].index,temp[1]);

        p = strtok (NULL, " ");
        temp[2] = p;
        strcpy( A[index].value,temp[2]);

        printf( "%s ",A[index].key);
        printf( "%s ",A[index].index);
        printf( "%s\n",A[index].value);
        index++;
      
      fclose(fp);
    

    if ( local_A_size != 0)
    
      if (my_rank == 0)
      
        printf( "File saved to memory of process %d!\n",my_rank);
        printf( "Process %d sending struct data to others...\n",my_rank);
      

      // send struct to all processes
      MPI_Scatter( &A,index, mpi_tuples_str, B, index, mpi_tuples_str, 0, MPI_COMM_WORLD;
      // MPI_Bcast( &tmp,index, MPI_CHAR, 0, MPI_COMM_WORLD);

      for(i=0;i<=local_A_size;i++)
      
          // MPI_Recv( &tmp, index, MPI_CHAR, 0, 10, MPI_COMM_WORLD, &status);
          printf( "I'm process %d and my result is: %s\n", my_rank, B[i].key);
      

      if (my_rank == 0) 
          printf("Data sent from process %d to others...\n", my_rank);
    

    else
    
      if (my_rank == 0) 
          printf( "Number of processes must be an exact divisor of %d, %d in not %ds divisor\n", index, size,index);
    

    // free memory used by mpi_tuples_str
    MPI_Type_free( &mpi_tuples_str);

    // Finalize
    MPI_Finalize();
    return 0;

我将 tuples_mini 文件设置为包含:

AsfAGHM5om  00000000000000000000000000000000  0000222200002222000022220000222200002222000000001111

当我在具有 4 核处理器的 ubuntu linux 14.04 上运行程序时,输出如下:

AsfAGHM5om 00000000000000000000000000000000 0000222200002222000022220000222200002222000000001111

File saved to memory of process 0!
Process 0 sending struct data to others...
I'm process 0 and my result is: AsfAGHM5om
I'm process 0 and my result is: 

然后这行的几十个:

I'm process 0 and my result is: 

接下来是这些行:

I'm process 0 and my result is: 
I'm process 0 and my result is: AsfAGHM5om
Data sent from process 0 to others...

所以代码中似乎有逻辑问题,但它没有seg fault

【讨论】:

嗯嗯嗯,我只是复制粘贴你更正的代码,我一直有相同的(有些我正在处理 0,我的结果是:),最后 `*** 检测到缓冲区溢出***: ./a.out 终止 ======= 回溯: ========= ... ======= 内存映射: ======== 。 .. ================================================ =====================================您的一个应用程序进程错误终止=退出代码:6 =清理剩余进程 = 您可以忽略以下清理消息顺便说一句,我在具有 6gb 内存和 64 位 ubuntu 14.04 的双核处理器上运行 mpich 我将其标记为已接受,因为问题是 mpich。我切换到openmpi,一切正常。像魅力一样编译的代码和运行时错误消失了。【参考方案2】:

关于发布代码的第二个版本

signal 6/sigabort 最可能的原因是因为第一次调用 strtok() 时将 NULL 作为第一个参数,而不是可见缓冲区的地址。

IMO:对strtok() 的首次调用应从程序中完全删除。

【讨论】:

以上是关于C-MPI 发送创建的带有字符数组的 typedef 结构的主要内容,如果未能解决你的问题,请参考以下文章

用HTTParty在body中发送带有数组的POST请求。

如何将带有图像的字节数组从 AS3 发送到 PHP?

从服务器向客户端发送带有 sun rpc 的结构数组

Boost Beast 将带有字节数组的 json 发送到客户端抛出 websocket

如何通过带有指针的函数传递 char 变量(示例已发送)?

带有包含数组的 Json 的 C# POST 请求