2013-12-08 16 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を持つ2つのプロセスが同じコミュニケードメイン内に実際に存在していることを、当然の提供、デッドロックに終了しません。コミュニケー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

は、相続人ソリューション:

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