2

MPI 標準 3.0 は、セクション 5.13 で次のように述べています。

最後に、マルチスレッドの実装では、1 つのプロセスで複数の同時実行の集団通信呼び出しを行うことができます。このような状況では、同じコミュニケーターが同じプロセスで 2 つの異なる集団通信呼び出しによって同時に使用されないようにするのは、ユーザーの責任です。

正しく実行されず(ただしコンパイルされ)、コアをダンプする次のプログラムを作成しました

void main(int argc, char *argv[])
{
int required = MPI_THREAD_MULTIPLE, provided, rank, size, threadID, threadProcRank ; 
MPI_Comm comm = MPI_COMM_WORLD ; 

MPI_Init_thread(&argc, &argv, required, &provided);
MPI_Comm_size(comm, &size);
MPI_Comm_rank(comm, &rank);

int buffer1[10000] = {0} ;
int buffer2[10000] = {0} ; 

#pragma omp parallel private(threadID,threadProcRank) shared(comm, buffer1)
{
    threadID = omp_get_thread_num();
    MPI_Comm_rank(comm, &threadProcRank);
    printf("\nMy thread ID is %d and I am in process ranked %d", threadID, threadProcRank);

    if(threadID == 0)
        MPI_Bcast(buffer1, 10000, MPI_INTEGER, 0, comm);

    If (threadID == 1)
        MPI_Bcast(buffer1, 10000, MPI_INTEGER, 0, comm);
}

    MPI_Finalize();
}

私の質問は次のとおりです。スレッド ID 0 とスレッド ID 1 を持つ各プロセスの 2 つのスレッドは、ルート プロセス (プロセス 0) で MPI_Send() として取得できるブロードキャスト呼び出しをポストします。残りのプロセスが宛先である MPI_Send() の 2 つのループとして解釈しています。宛先プロセスは、スレッド ID 0 とスレッド ID 1 にも MPI_Bcast() をポストします。これらは、2 つのスレッドの各プロセスによってポストされた 2 つの MPI_Recv() と見なすことができます。MPI_Bcast() は同一であるため、プロセス 0 (ルート) から送信されたメッセージを受信する際に一致の問題は発生しないはずです。しかし、それでもプログラムは機能しません。なんで ?同じコミュニケーターの異なる/同じコレクティブでメッセージが混同される可能性があるためですか? そして、MPI(mpich2)はその可能性を見て、

4

1 に答える 1

4

まず第一にprovided、MPI 実装が実際に提供されたスレッド サポート レベルを返す場所の値をチェックしていません。標準では、このレベルを要求されたレベルよりも低くすることが許可されており、適切な MPI アプリケーションでは次のようになります。

MPI_Init_thread(&argc, &argv, required, &provided);
if (provided < required)
{
    printf("Error: MPI does not provide the required thread support\n");
    MPI_Abort(MPI_COMM_WORLD, 1);
    exit(1);
}

次に、このコード行は冗長です。

MPI_Comm_rank(comm, &threadProcRank);

MPI のスレッドには個別のランクはありません。プロセスのみにランクがあります。いわゆるエンドポイントを MPI 3.0 に導入するという提案がありました。これにより、単一のプロセスが複数のランクを持ち、それらを異なるスレッドにバインドできるようになりましたが、標準の最終バージョンにはなりませんでした。

3 番目に、両方の集合体で同じバッファー変数を使用しています。buffer1あなたの意図は、スレッド0の呼び出しとスレッド1の呼び出しで使用することだったと思いますbuffer2。また、FortranMPI_INTEGERで対応するデータ型です。INTEGERCint型の場合、対応する MPI データ型はMPI_INT.

第 4 に、MPI_BCASTのループとしてのMPI_SENDと対応するMPI_RECVの解釈は、まさに解釈です。実際には、実装は大きく異なります。こちらを参照してください。たとえば、初期ネットワーク セットアップ レイテンシが物理データ送信時間よりもはるかに長い小さなメッセージでは、コレクティブのレイテンシを最小限に抑えるために、2 進ツリーと 2 項ツリーが使用されます。通常、大きなメッセージは多くのセグメントに分割され、パイプラインを使用してルート ランクから他のすべてのセグメントにセグメントが渡されます。ツリー分散の場合でも、メッセージをセグメント化できます。

問題は、実際には各集合操作が同じタグ (通常は負のタグ値) を持つメッセージを使用して実装されることです (これらはアプリケーション プログラマが使用することを許可されていません)。つまりMPI_Bcast、あなたの場合の両方の呼び出しが同じタグを使用してメッセージを送信し、ランクが同じでコミュニケーターが同じであるため、メッセージがすべて混同されることを意味します。したがって、別々のコミュニケーターでのみ並行コレクティブを実行するための要件。

プログラムがクラッシュする理由は 2 つあります。理由の 1 つは、MPI ライブラリが を提供していないことMPI_THREAD_MULTIPLEです。2 番目の理由は、メッセージが 2 つの不均一なサイズのチャンク (たとえば、最初の部分が大きく、2 番目の部分が小さい) に分割されている場合です。両方の集合呼び出し間の干渉により、2 番目のスレッドは、2 番目の小さいチャンクを待機している間に、最初のスレッドに向けられた大きな最初のチャンクを受信する可能性があります。その結果、メッセージが切り捨てられ、アボート MPI エラー ハンドラが呼び出されます。これは通常、segfault やコア ダンプにはならないので、MPICH2 が単にスレッド セーフとしてコンパイルされていないと思います。

これは MPICH2 固有ではありません。Open MPI およびその他の実装も、同じ制限を受けやすい傾向があります。

于 2013-07-14T09:47:09.827 に答える