2013-02-26 31 views
5

Tôi gặp vài vấn đề với chương trình MPI trong C. Tôi muốn gửi hai tin nhắn với MPI_Send từ nô lệ đến chủ (sử dụng MPI_Send, MPI_Irecv và MPI_Test), nhưng chỉ có thông báo đầu tiên hoạt động. Sau đó, tôi đã có một vòng lặp vô hạn và tôi luôn nhận được một tin nhắn từ nô lệ -1 (theo status.MPI_Source).Vòng lặp vô hạn sử dụng MPI_Irecv và MPI_Test

Vì vậy, tôi không hiểu tại sao tôi nhận được tất cả những thông điệp từ một quá trình không rõ (-1) ...

Mã của tôi:

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

} 

Cảm ơn.

ps: xin lỗi vì tiếng anh của tôi

Trả lời

4

Vấn đề là chủ chỉ nhận được một bài đăng. Bạn cần di chuyển cuộc gọi đến số MPI_Irecv bên trong vòng lặp, tại thời điểm MPI_Test trả lại thành công (bên trong khối if (status.MPI_SOURCE != -1)), để các tin nhắn tiếp theo có thể được nhận.

9

Có một điều là bạn phải gọi MPI_Irecv mỗi khi bạn đang mong đợi một tin nhắn. Vì vậy, trong trường hợp của bạn, bạn phải gọi nó 2 lần. Không nhiều không ít.

Cho phép xem xét mã được thay đổi bằng cách chỉ di chuyển vòng lặp bên trong cuộc gọi MPI_Irecv. Không chính xác. Sẽ không làm việc.

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

Giả sử thời gian ngẫu nhiên của việc cung cấp các thông điệp sended bởi nô lệ (mà luôn luôn là trường hợp khi chúng ta đang nói về hệ thống phân phối hoặc chủ đề) thật dễ dàng để tưởng tượng tình huống đó: Moment thời gian | sự kiện

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 

Có hai giải pháp. Bạn có thể làm chậm quá trình Master bằng cách gọi sleep (3) trước khi while loop, do đó, nó chắc chắn sẽ bắt đầu sau đó gọi là MPI_Send.

Thứ hai, cách tiếp cận kỹ thuật tốt hơn là gọi MPI_Irecv chỉ khi chúng tôi đang mong đợi tin nhắn. Ban đầu gọi MPI_Irecv và gán giá trị 0 cho cờ. Sau khi chúng tôi nhận lại cờ thay đổi tin nhắn thành -1 và chỉ gọi MPI_Irecv khi cờ có giá trị -1.

Đây là mã nó hoạt động:

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

}