2013-02-26 15 views
5

Mam kilka problemów z programem MPI w C. Chcę wysłać dwa komunikaty z MPI_Send z slaves do master (używając MPI_Send, MPI_Irecv i MPI_Test), ale działa tylko pierwszy komunikat. Potem mam nieskończoną pętlę i zawsze otrzymuję komunikat od slave -1 (zgodnie ze stanem. MPI_Source).Nieskończona pętla korzystająca z MPI_Irecv i MPI_Test

Więc nie rozumiem, dlaczego odbierać wszystkie te wiadomości z nieznanego procesu (-1) ...

Mój kod:

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

} 

Dzięki.

PS: Przepraszam za mój angielski

Odpowiedz

4

Problem polega na tym, że mistrz nigdy księguje tylko jeden otrzymać. Będziesz musiał przenieść wywołanie do MPI_Irecv w pętli, w punkcie, w którym MPI_Test powrócił z sukcesem (wewnątrz bloku if (status.MPI_SOURCE != -1)), dzięki czemu można odbierać kolejne wiadomości.

9

Jedną z rzeczy jest to, że musisz zadzwonić do MPI_Irecv za każdym razem, gdy spodziewasz się wiadomości. Więc w twoim przypadku musisz zadzwonić 2 razy. Nie więcej nie mniej.

Pozwala spojrzeć na kod zmieniony tylko przez poruszającą się wewnętrzną pętlę wywołania MPI_Irecv. To nie jest poprawne. Nie będzie działać.

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

Zakładając losowy czas dostarczania wiadomości Rozesłano przez niewolników (który jest zawsze w przypadku, gdy mówimy o rozproszonych systemów lub wątków) to łatwo sobie wyobrazić taką sytuację: momencie czasu | zdarzenie

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 

Istnieją dwa rozwiązania. Możesz spowolnić proces Master poprzez wywołanie sleep (3) przed pętlą while, więc na pewno zacznie się później, a następnie zostanie wywołany MPI_Send.

Po drugie, lepszym podejściem inżynieryjnym jest wywoływanie MPI_Irecv tylko wtedy, gdy oczekujemy wiadomości. Najpierw wywołaj MPI_Irecv i przypisz wartość 0 do flagi. Po otrzymaniu wiadomości zmień flagę ponownie na -1 i wywołaj MPI_Irecv tylko wtedy, gdy flaga ma wartość -1.

Oto kod działa:

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

} 
Powiązane problemy