2013-02-26 117 views
5

我在C中使用MPI程序時遇到了一些問題。我想發送MPI_Send從從站到主站(使用MPI_Send,MPI_Irecv和MPI_Test)的兩條消息,但只有第一條消息有效。之後,我有一個無限循環,我總是收到來自slave的消息-1(根據status.MPI_Source)。使用MPI_Irecv和MPI_Test的無限循環

,所以我不明白爲什麼我收到一個未知的過程(-1),所有這些消息......

我的代碼:

#include <stdio.h> 
#include <mpi.h> 
#include <sys/time.h> 

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

int rank, size; 
MPI_Status status; 

/* Init */ 
MPI_Init(&argc, &argv); 
MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
MPI_Comm_size(MPI_COMM_WORLD, &size); 

if (rank != 0) { // Slaves 
    int buf; 

    if (rank == 1) { 
     buf = 1; 
     MPI_Send(&buf, 1, MPI_INT, 0, 0, MPI_COMM_WORLD); 
    } 
    if (rank == 2) { 
     buf = 2; 
     MPI_Send(&buf, 1, MPI_INT, 0, 0, MPI_COMM_WORLD); 
    } 

} 
else { // Master 
    int sum = 0; 
    int flag, res; 
    MPI_Request request; 
    MPI_Status status; 

    MPI_Irecv(&res, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &request); 

    while (1) { 
     flag = 0; 

     MPI_Test(&request, &flag, &status); 

     if (flag != 0) { 
      printf("recv : %d, slave : %d\n", res, status.MPI_SOURCE); 
      if (status.MPI_SOURCE != -1) 
       sum += res; 
     } 
     else 
      printf("fail!\n"); 

     if (sum == 3) 
      break; 
    } 

    printf("sum : %d\n", sum); 
} 

MPI_Finalize(); 
return 0; 

} 

感謝。

ps:對不起,我的英語

回答

4

問題是,主人只發佈一個接收。您需要將呼叫轉移到循環內的MPI_Irecv,此時MPI_Test成功返回(位於if (status.MPI_SOURCE != -1)塊內),以便可以接收後續消息。

9

有一件事是,您每次需要消息時都必須調用MPI_Irecv。所以在你的情況下,你必須調用它2次。沒有更多,不少。

讓我們看看僅通過在循環內移動MPI_Irecv調用而改變的代碼。 這是不正確的。不管用。

else { // Master 
int sum = 0; 
int flag, res; 
MPI_Request request; 
MPI_Status status; 

while (1) { 
    flag = 0; 
    MPI_Irecv(&res, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &request); 
    MPI_Test(&request, &flag, &status); 
    if (flag != 0) { 
     printf("recv : %d, slave : %d\n", res, status.MPI_SOURCE); 
     if (status.MPI_SOURCE != -1) 
      sum += res; 
    } 
    else 
     printf("fail!\n"); 

    if (sum == 3) 
     break; 
} 

假設提供由奴隸sended消息的隨機時間(這始終是當我們談論分佈式系統或線程的情況下),可以很容易地想象這種情況: 時刻的時間|事件

0    | called first MPI_Irecv, allocated memory for MPI_Request object 
1    | called second MPI_Irecv, allocated memory for MPI_Request (lets say) object2 
2    | called third MPI_Irecv, allocated memory for MPI_Request object3 
3    | called MPI_Send in slave no. 1 
4    | called MPI_Send in slave no. 2 
5    | received message by master from slave no. 1, filled object, flag variable still 0 because its related to object3 
6    | received message by master from slave no. 2, filled object2, flag variable still 0 because its related to object3 
7,8,9...  | infinite loop, flag still has value 0 
n   | error: MPI_Irecv(147): MPI_Irecv(buf=0x7fffecfa60c4, count=1, MPI_INT, src=MPI_ANY_SOURCE, tag=MPI_ANY_TAG, MPI_COMM_WORLD, request=0x7fffecfa60c8) 
MPID_Irecv(53): failure occurred while allocating memory for a request object 

有兩種解決方案。您可以通過在while循環之前調用sleep(3)來減慢主進程,所以它肯定會在稍後調用MPI_Send的時候啓動。

其次,更好的工程方法是隻在我們期待消息時調用MPI_Irecv。最初調用MPI_Irecv並將值賦給該標誌。在我們將消息更改標誌再次接收到-1後,僅當標誌具有-1值時才調用MPI_Irecv。

這裏是代碼它的工作原理

#include <stdio.h> 
#include <mpi.h> 
#include <sys/time.h> 

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

int rank, size; 
MPI_Status status; 

/* Init */ 
MPI_Init(&argc, &argv); 
MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
MPI_Comm_size(MPI_COMM_WORLD, &size); 

if (rank != 0) { // Slaves 
    int buf; 

    if (rank == 1) { 
     buf = 1; 
     MPI_Send(&buf, 1, MPI_INT, 0, 0, MPI_COMM_WORLD); 
    } 
    if (rank == 2) { 
     buf = 2; 
     MPI_Send(&buf, 1, MPI_INT, 0, 0, MPI_COMM_WORLD); 
    } 

} 
else { // Master 
    int sum = 0; 
    int flag = -1, res; 
    MPI_Request request; 
    MPI_Status status; 
    while (1) { 
    if(flag != 0) 
    { 
     MPI_Irecv(&res, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &request); 
     flag = 0; 
    } 
     MPI_Test(&request, &flag, &status); 

     if (flag != 0) { 
      printf("recv : %d, slave : %d\n", res, status.MPI_SOURCE); 
      if (status.MPI_SOURCE != -1) 
       sum += res; 
     flag = -1; 
     } 


     if (sum == 3) 
      break; 
    } 

    printf("sum : %d\n", sum); 
} 

MPI_Finalize(); 
return 0; 

}