2013-12-08 1 views
5

이 코드가 교착 상태를 일으킬 수있는 경우 MPI를 실험 중이며 방황했습니다.MPI 교착 상태

MPI_Comm_rank (comm, &my_rank); 
if (my_rank == 0) { 
    MPI_Send (sendbuf, count, MPI_INT, 1, tag, comm); 
    MPI_Recv (recvbuf, count, MPI_INT, 1, tag, comm, &status); 
} else if (my_rank == 1) { 
    MPI_Send (sendbuf, count, MPI_INT, 0, tag, comm); 
    MPI_Recv (recvbuf, count, MPI_INT, 0, tag, comm, &status); 
} 

답변

9

MPI_Send은 차단 될 수도 있고 차단되지 않을 수도 있습니다. 보낸 사람이 보낸 사람 버퍼를 다시 사용할 수있을 때까지 차단됩니다. 일부 구현은 버퍼가 하위 통신 레이어로 전송되면 호출자에게 반환됩니다. 다른 쪽에서 일치하는 MPI_Recv()이있을 때 다른 사람이 발신자에게 돌아갑니다. 따라서이 프로그램이 교착 상태에 빠질 지 여부는 MPI 구현에 달려 있습니다. ,

MPI_Comm_rank (comm, &my_rank); 
if (my_rank == 0) { 
    MPI_Send (sendbuf, count, MPI_INT, 1, tag, comm); 
    MPI_Recv (recvbuf, count, MPI_INT, 1, tag, comm, &status); 
} else if (my_rank == 1) { 
    MPI_Recv (recvbuf, count, MPI_INT, 0, tag, comm, &status); 
    MPI_Send (sendbuf, count, MPI_INT, 0, tag, comm); 
} 
항상

모든 MPI_Send()에 대한 페어링 MPI_Recv()이 있어야한다는주의 :이 때문에 프로그램의

가능 교착 상태가되지 않도록 당신이 그것을 rewritting 고려할 수있다, 다른 MPI 구현들 사이에서 다르게 작동 둘 다 "평행"합니다. 예를 들어 페어링 send/recv 호출이 시간상으로 정렬되지 않기 때문에 교착 상태가 될 수 있습니다. 그들은 서로 교차 :

RANK 0       RANK 1 
----------      ------- 
MPI_Send() ---   ---- MPI_Send() | 
       ---  ---     | 
       ------      | 
        --       | TIME 
       ------      | 
       ---  ---     | 
MPI_Recv() <--   ---> MPI_Recv() v 

이 프로세스를 다른 방법에 물론 제공 교착 상태에 끝나지 않을 것 같은 의사 소통 영역에서의 계급 0과 1 두 개의 프로세스가 실제로 있다는 것을. 통신부 com의 크기가 1 레벨 (단 0)를 허용하지 않는 경우

RANK 0       RANK 1 
----------      ------- 
MPI_Send() ------------------> MPI_Recv() | 
              | TIME 
              | 
MPI_Recv() <------------------ MPI_Send() v 

상기 고정 프로그램이 실패 할 수있다. 이렇게하면 if-elseelse 경로를 사용하지 않으므로 MPI_Send()을 수신 대기하는 프로세스가없고 순위 0이 교착 상태가됩니다.

현재 통신 레이아웃을 사용해야하는 경우 비 블로킹 샌드 대신 대신 MPI_Isend() 또는 MPI_Issend()을 사용하면 교착 상태를 피할 수 있습니다.

3

@mcleod_ideafix의 게시물은 매우 좋습니다. 비 차단 MPI 호출에 대해 몇 가지 더 추가하고 싶습니다.

대부분의 MPI 구현 방식은 사용자 버퍼의 데이터를 다른 곳으로 복사한다는 것입니다. 구현 내부의 버퍼 일 수도 있습니다. 올바른 종류의 네트워크에서 더 나은 것이 될 수도 있습니다. 해당 데이터가 사용자 버퍼에서 복사되고 응용 프로그램에서 버퍼를 다시 사용할 수있는 경우 MPI_SEND 호출이 반환됩니다. 이는 일치하는 MPI_RECV이 호출되기 전일 수도 있고 그렇지 않을 수도 있습니다. 보내는 데이터가 클수록 MPI_RECV 전화가 걸릴 때까지 메시지가 차단 될 가능성이 높습니다.

이 문제를 방지하는 가장 좋은 방법은 비 차단 호출 MPI_IRECVMPI_ISEND을 사용하는 것입니다. 이렇게하면 MPI_IRECV을 먼저 게시 한 다음 MPI_ISEND으로 전화를 걸 수 있습니다. 이렇게하면 메시지가 도착할 때 여분의 복사본이 생기는 것을 피할 수 있습니다 (버퍼를 보유 할 버퍼가 이미 MPI_IRECV을 통해 사용 가능하므로 작업 속도가 빨라지고 교착 상태가 방지됩니다). 그래서 지금 당신의 코드는 다음과 같습니다

MPI_Comm_rank (comm, &my_rank); 
if (my_rank == 0) { 
    MPI_Irecv (recvbuf, count, MPI_INT, 1, tag, comm, &status, &requests[0]); 
    MPI_Isend (sendbuf, count, MPI_INT, 1, tag, comm, &requests[1]); 
} else if (my_rank == 1) { 
    MPI_Irecv (recvbuf, count, MPI_INT, 0, tag, comm, &status, &requests[0]); 
    MPI_Isend (sendbuf, count, MPI_INT, 0, tag, comm, &requests[1]); 
} 
MPI_Waitall(2, request, &statuses); 
0

을 mcleod_ideafix이 코드가 교착 상태가 발생할 수 있습니다 설명한다. 여기 당신은 이동 : Explanation and two possible issue Solutions, one by rearranging execution order, one by async send recv calls

가 Heres는 비동기와 솔루션을 호출

if (rank == 0) { 
     MPI_Isend(..., 1, tag, MPI_COMM_WORLD, &req); 
     MPI_Recv(..., 1, tag, MPI_COMM_WORLD, &status); 
     MPI_Wait(&req, &status); 
} else if (rank == 1) { 
     MPI_Recv(..., 0, tag, MPI_COMM_WORLD, &status); 
     MPI_Send(..., 0, tag, MPI_COMM_WORLD); 
}