2014-03-03 1 views
0

Open MPI 메시지 통신을 사용하여 장벽을 통한 동기화를 연습하고 있습니다. 컨테이너라는 구조체의 배열을 만들었습니다. 각 컨테이너는 오른쪽에있는 이웃과 연결되어 있으며 양 끝의 두 요소도 연결되어 원을 형성합니다.Open MPI (C 프로그램)에 걸린 배리어 호출

main() 테스트 클라이언트에서 다중 프로세스 (mpiexec -n 5 ./a.out)를 사용하여 MPI를 실행하며 barrier() 함수를 호출하여 동기화 될 예정이지만 내 코드는 다음과 같습니다. 마지막 과정에 갇혔다. 디버깅에 대한 도움을 찾고 있습니다.

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

typedef struct container { 
    int labels;     
    struct container *linked_to_container;  
    int sense; 
} container; 

container *allcontainers; /* an array for all containers */ 
int size_containers_array; 

int get_next_container_id(int current_container_index, int max_index) 
{ 
    if (max_index - current_container_index >= 1) 
    { 
     return current_container_index + 1; 
    } 
    else 
     return 0;  /* elements at two ends are linked */ 
} 

container *get_container(int index) 
{ 
    return &allcontainers[index]; 
} 


void container_init(int num_containers) 
{ 
    allcontainers = (container *) malloc(num_containers * sizeof(container)); /* is this right to malloc memory on the array of container when the struct size is still unknown?*/ 
    size_containers_array = num_containers; 

    int i; 
    for (i = 0; i < num_containers; i++) 
    { 
     container *current_container = get_container(i); 
     current_container->labels = 0; 
     int next_container_id = get_next_container_id(i, num_containers - 1);  /* max index in all_containers[] is num_containers-1 */ 
     current_container->linked_to_container = get_container(next_container_id); 
     current_container->sense = 0; 
    } 
} 

void container_barrier() 
{ 
    int current_container_id, my_sense = 1; 
    int tag = current_container_id; 
    MPI_Request request[size_containers_array]; 
    MPI_Status status[size_containers_array]; 

    MPI_Comm_rank(MPI_COMM_WORLD, &current_container_id); 
    container *current_container = get_container(current_container_id); 

    int next_container_id = get_next_container_id(current_container_id, size_containers_array - 1); 

    /* send asynchronous message to the next container, wait, then do blocking receive */ 
    MPI_Isend(&my_sense, 1, MPI_INT, next_container_id, tag, MPI_COMM_WORLD, &request[current_container_id]); 
    MPI_Wait(&request[current_container_id], &status[current_container_id]); 
    MPI_Recv(&my_sense, 1, MPI_INT, next_container_id, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 

} 

void free_containers() 
{ 
    free(allcontainers); 
} 

int main(int argc, char **argv) 
{ 
    int my_id, num_processes; 
    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &num_processes); 
    MPI_Comm_rank(MPI_COMM_WORLD, &my_id); 

    container_init(num_processes); 

    printf("Hello world from thread %d of %d \n", my_id, num_processes); 
    container_barrier(); 
    printf("passed barrier \n"); 



    MPI_Finalize(); 
    free_containers(); 

    return 0; 
} 

답변

1

문제는 통화의 시리즈 : :

MPI_Isend() 
MPI_Wait() 
MPI_Recv() 

이 혼란의 일반적인 원인은 아래에있는 내 코드를 참조하십시오. MPI에서 "nonblocking"호출을 사용하면 MPI 라이브러리에 일부 데이터 (my_sense)를 사용하여 일부 작업 (전송)을 수행한다고 말합니다. MPI는 MPI_Request 완료 함수가 완료 될 때까지 호출이 완료된다는 보장하에 MPI_Request 개체를 반환합니다.

여기에서 문제가되는 것은 을 모든 등급에서 호출하기 전에 MPI_Isend으로 전화하고 바로 MPI_Wait으로 전화하는 것입니다. 즉, MPI에게 데이터를 넣을 곳을 MPI_Recv (데이터를 넣으려는 사람에게 my_sense)으로 말한 적이 없기 때문에 모든 전송 호출은 대기 상태가되지만 실제로 갈 곳이 없습니다.

시간의 일부로 작동하는 이유는 MPI가 일들이 항상 완벽하게 동기화되지 않을 것이라고 생각하기 때문입니다. 더 작은 메시지가 있다면 MPI는 약간의 버퍼 공간을 예약하고 나중에 MPI_Recv으로 데이터를 이동할 위치를 MPI에게 알릴 때까지 MPI_Send 작업이 완료되고 잠시 동안 임시 공간에 데이터가 저장됩니다. 결국에는 더 이상 작동하지 않습니다. 버퍼가 가득 차면 실제로 메시지 수신을 시작해야합니다. 이는 사용자가 작업 순서를 전환해야 함을 의미합니다. 대신 블로킹 전송을하고, 당신이 먼저, 다음 차단 송신을 수신 비 차단을해야, 다음을 기다리는 당신의 완료가 나타납니다

MPI_Irecv() 
MPI_Send() 
MPI_Wait() 

다른 옵션은 블로킹으로 두 기능을 설정하는 것입니다 기능을 대신 사용 MPI_Waitall :

MPI_Isend() 
MPI_Irecv() 
MPI_Waitall() 

이 마지막 옵션은 일반적으로 최고입니다. 주의해야 할 유일한 점은 자신의 데이터를 덮어 쓰지 않는 것입니다. 지금은 보내기와 받기 작업 모두에 동일한 버퍼를 사용하고 있습니다. 이 두 가지가 동시에 발생하면 주문에 대한 보장이 없습니다. 일반적으로 이것은 차이를 만들지 않습니다. 메시지를 처음으로 보내거나받을 지 여부는 중요하지 않습니다. 그러나이 경우에는 그렇지 않습니다. 데이터를 처음 받으면 수신 작업 이전에 가지고 있던 데이터를 보내는 대신 동일한 데이터를 다시 보냅니다. 임시 버퍼를 사용하여 데이터를 준비하고 안전 할 때 임시 위치로 이동할 수 있습니다.