2012-03-25 41 views
27

我已經定義了一個自定義結構,並希望使用MPI_Bsend(或MPI_Send)將它發送到另一個MPI進程 。C中的結構序列化和通過MPI傳輸

這裏是我的結構:

struct car{ 
    int shifts; 
    int topSpeed; 
}myCar; 

然而,除了基本類型MPI似乎並不支持直接複雜的數據類型,如上述結構的「傳輸」。我聽說我可能不得不使用「序列化」。 我應該如何處理它並將'myCar'發送給進程5?

回答

48

Jeremiah是對的 - MPI_Type_create_struct是去這裏的路。

重要的是要記住,MPI是一個圖書館,不是內置於語言;所以它不能「看到」什麼樣的結構看起來像序列化它本身。因此,要發送複雜的數據類型,您必須明確定義其佈局。在具有對序列化的本地支持的語言中,一組MPI包裝器可以協調地使用它;例如mpi4py利用python的pickle來透明地發送複雜的數據類型;但在C中,你必須捲起袖子並自己動手。

爲了您的結構,它看起來像這樣:

#include <stdio.h> 
#include <stdlib.h> 
#include <mpi.h> 
#include <stddef.h> 

typedef struct car_s { 
     int shifts; 
     int topSpeed; 
} car; 

int main(int argc, char **argv) { 

    const int tag = 13; 
    int size, rank; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 

    if (size < 2) { 
     fprintf(stderr,"Requires at least two processes.\n"); 
     exit(-1); 
    } 

    /* create a type for struct car */ 
    const int nitems=2; 
    int   blocklengths[2] = {1,1}; 
    MPI_Datatype types[2] = {MPI_INT, MPI_INT}; 
    MPI_Datatype mpi_car_type; 
    MPI_Aint  offsets[2]; 

    offsets[0] = offsetof(car, shifts); 
    offsets[1] = offsetof(car, topSpeed); 

    MPI_Type_create_struct(nitems, blocklengths, offsets, types, &mpi_car_type); 
    MPI_Type_commit(&mpi_car_type); 

    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    if (rank == 0) { 
     car send; 
     send.shifts = 4; 
     send.topSpeed = 100; 

     const int dest = 1; 
     MPI_Send(&send, 1, mpi_car_type, dest, tag, MPI_COMM_WORLD); 

     printf("Rank %d: sent structure car\n", rank); 
    } 
    if (rank == 1) { 
     MPI_Status status; 
     const int src=0; 

     car recv; 

     MPI_Recv(&recv, 1, mpi_car_type, src, tag, MPI_COMM_WORLD, &status); 
     printf("Rank %d: Received: shifts = %d topSpeed = %d\n", rank, 
       recv.shifts, recv.topSpeed); 
    } 

    MPI_Type_free(&mpi_car_type); 
    MPI_Finalize(); 

    return 0; 
} 
+0

感謝您提供非常全面和快速的回​​復。對此,我真的非常感激。你已經完全覆蓋了我。 (但是我認爲你忘了在頂部導致,否則編譯器會給出錯誤。) – kstratis 2012-03-26 00:39:55

+0

你是對的 - 需要offsetof()。我已經適當地更新了代碼。 – 2012-03-26 02:05:07

5

查看MPI_Type_create_struct爲您的對象構建自定義MPI數據類型。使用它的一個例子是http://beige.ucs.indiana.edu/I590/node100.html

+0

我還是有點困惑..假設我定義了MPI結構並且現在想要使用它。您給出的鏈接狀態:MPI_Type_create_struct(5,array_of_block_lengths,array_of_displacements, array_of_types,&new_type);我現在應該做一些類似myCar =&new_type的事情嗎? – kstratis 2012-03-25 23:07:52

+0

更重要的是...你能給我一個簡單但具體的例子來創建和傳輸特定的結構嗎? – kstratis 2012-03-25 23:28:43

+0

問題解決。您提供的鏈接提供了所有的「理論」,但由於位移和低級細節,很容易讓業餘程序員混淆。但它似乎正好描述了底下的機制。 – kstratis 2012-03-26 00:41:27

6

雖然喬納森·德西的答案是正確的,這是過於複雜。 MPI提供更簡單和不太常見的類型構造函數,更適合您的問題。只有當你有不同的基類型(例如,一個int和一個浮點數)時才需要MPI_Type_create_struct

對於你的榜樣,一些更好的解決方案存在:

  • 假設兩個整數在一個連續的內存區域對齊(即,像一個整數數組),你不需要導出類型在所有。只需發送/接收MPI_INT類型的兩個元素與car類型的變量的地址被用作發送/接收緩衝區:

    MPI_Send(&send, 2, MPI_INT, dest, tag, MPI_COMM_WORLD); 
    MPI_Recv(&recv, 2, MPI_INT, src, tag, MPI_COMM_WORLD, &status); 
    
  • 如果要使用派生的數據類型(例如,對於可讀性或它的樂趣),你可以使用MPI_Type_contiguous對應於數組:

    MPI_Type_contiguous(2, MPI_INT, &mpi_car_type); 
    
  • 如果兩個整數對準不同的(最有可能並非如此,但它是依賴於機器和大量存在的MPI實現不同的平臺),你可以使用MPI_Type_indexed_block:這需要位移的陣列(如MPI_Type_create_struct),但只有一個OLDTYPE參數和每塊的塊長度由定義爲1:

    MPI_Aint offsets[2]; 
    offsets[0] = offsetof(car, shifts) ; //most likely going to be 0 
    offsets[1] = offsetof(car, topSpeed); 
    MPI_Type_indexed_block(2, offsets, MPI_INT); 
    

儘管其他方案是語義上正確的,它閱讀起來很困難,可能會導致很大的性能損失。