21

このウェブサイトによると、の使用法MPI::COMM_WORLD.Send(...)はスレッドセーフです。ただし、私のアプリケーションでは、デッドロックが発生したり、セグメンテーション違反が発生したりすることがよくあります(常にではありません)。MPI::COMM_WORLDメソッドの各呼び出しをとで囲むmutex.lock()と、mutex.unlock()デッドロックとsegfaultが一貫して削除されます。

これが私がスレッドを作成する方法です:

const auto communicator = std::make_shared<Communicator>();
std::vector<std::future<size_t>> handles;
for ( size_t i = 0; i < n; ++i )
{
   handles.push_back(std::async(std::launch::async, foo, communicator));
}
for ( size_t i = 0; i < n; ++i )
{
   handles[i].get();
}

Communicatorメンバーを持ち、やstd::mutexなどのメソッドを排他的に呼び出すクラスです。MPIで送受信する他の方法は使用していません。引数としてを取ります。MPI::COMM_WORLD.Send()MPI::COMM_WORLD.Recv()fooconst std::shared_ptr<Commmunicator> &

私の質問:MPIによって約束されたスレッドセーフは、によって作成されたスレッドと互換性がありませんstd::asyncか?

4

2 に答える 2

29

MPIのスレッドセーフはそのままでは機能しません。まず、実装が実際に一度にMPI呼び出しを行う複数のスレッドをサポートしていることを確認する必要があります。Open MPIなどの一部のMPI実装では、ビルド時にライブラリを特別なオプションで構成する必要があります。次に、適切なスレッドサポートレベルで初期化するようにMPIに指示する必要があります。現在、MPI標準では、次の4つのレベルのスレッドサポートが定義されています。

  • MPI_THREAD_SINGLE-ユーザーコードがシングルスレッドであることを意味します。これは、使用されている場合にMPIが初期化されるデフォルトのレベルですMPI_Init()
  • MPI_THREAD_FUNNELED-ユーザーコードがマルチスレッドであるが、メインスレッドのみがMPI呼び出しを行うことを意味します。メインスレッドは、MPIライブラリを初期化するスレッドです。
  • MPI_THREAD_SERIALIZED-ユーザーコードはマルチスレッドですが、MPIライブラリへの呼び出しはシリアル化されていることを意味します。
  • MPI_THREAD_MULTIPLE-ユーザーコードがマルチスレッドであり、すべてのスレッドが同期なしでいつでもMPI呼び出しを行うことができることを意味します。

スレッドサポートを使用してMPIを初期化するには、次MPI_Init_thread()の代わりにを使用する必要がありMPI_Init()ます。

int provided;

MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
if (provided < MPI_THREAD_MULTIPLE)
{
    printf("ERROR: The MPI library does not have full thread support\n");
    MPI_Abort(MPI_COMM_WORLD, 1);
}

廃止された(そしてMPI-3から削除された)C ++バインディングを持つ同等のコード:

int provided = MPI::Init_thread(argc, argv, MPI::THREAD_MULTIPLE);
if (provided < MPI::THREAD_MULTIPLE)
{
    printf("ERROR: The MPI library does not have full thread support\n");
    MPI::COMM_WORLD.Abort(1);
}

スレッドサポートレベルは次のように順序付けられます:MPI_THREAD_SINGLE<<< MPI_THREAD_FUNNELED、したがって、他の提供されたレベルは、数値が低くなります-そのため、上記のMPI_THREAD_SERIALIZEDコードはそのように記述されています。MPI_THREAD_MULTIPLEMPI_THREAD_MULTIPLEif (...)

MPI_Init(&argc, &argv)と同等MPI_Init_thread(&argc, &argv, MPI_THREAD_SINGLE, &provided)です。実装は、要求されたレベルで正確に初期化する必要はありません。むしろ、provided出力引数で返される他のレベル(より高いまたはより低い)で初期化することができます。

詳細については、MPI標準の§12.4を参照してください。ここから無料で入手できます。

ほとんどのMPI実装では、レベルでのスレッドサポートMPI_THREAD_SINGLEは、実際にはレベルで提供されるものと同等です。これは、実際MPI_THREAD_SERIALIZEDにあなたが観察したものとまったく同じです。

使用するMPI実装を指定していないので、ここに便利なリストがあります。

をサポートするには、OpenMPIを適切なフラグを有効にしてコンパイルする必要があることはすでに述べましたMPI_THREAD_MULTIPLE。ただし、別の問題があります。そのInfiniBandコンポーネントはスレッドセーフではないため、Open MPIは、フルスレッドサポートレベルで初期化された場合、ネイティブのInfiniBand通信を使用しません。

Intel MPIには、完全なマルチスレッドをサポートするものとサポートしないものの2つの異なる種類があります。マルチスレッドサポートは-mt_mpi、MTバージョンとのリンクを有効にするオプションをMPIコンパイララッパーに渡すことで有効になります。このオプションは、OpenMPサポートまたは自動並列化機能が有効になっている場合にも暗示されます。フルスレッドサポートが有効になっている場合、IMPIのInfiniBandドライバーがどのように機能するかわかりません。

MPICH(2)はInfiniBandをサポートしていないため、スレッドセーフであり、おそらく最新バージョンはそのままでMPI_THREAD_MULTIPLEサポートを提供します。

MVAPICHは、Intel MPIが構築される基盤であり、InfiniBandをサポートします。InfiniBandを搭載したマシンで使用した場合、フルスレッドサポートレベルでどのように動作するかわかりません。

最近の多くのコンピューティングクラスターはInfiniBandファブリックを使用しているため、マルチスレッドのInfiniBandサポートに関する注意事項は重要です。IBコンポーネント(openibOpen MPIのBTL)を無効にすると、ほとんどのMPI実装は、TCP / IP(Open MPIのBTL)などの別のプロトコルに切り替わりますtcp。これにより、通信がはるかに遅くなり、潜在的になります。

于 2013-02-12T16:31:34.110 に答える
1

MPIスレッドセーフには4つのレベルがありますが、すべての実装でサポートされているわけではありません。MPI_THREAD_SINGLE、MPI_THREAD_FUNNELED、MPI_THREAD_SERIALIZED、およびMPI_THREAD_MULTIPLEです。プロセスがMPI関数を同時に呼び出す可能性のある複数のスレッドを持つことを可能にする最後のものは、おそらくあなたが興味を持っているものです。したがって、まず、実装がMPI_THREAD_SERIALIZEDをサポートしていることを確認する必要があります。

スレッドセーフの必要なレベルは、の呼び出しで指定する必要がありますMPI_Init_thread。呼び出した後MPI_Init_thread、自分で作成したブースト(POSIX)スレッドでMPI関数を安全に呼び出すことができるはずです。

于 2013-02-12T16:32:00.443 に答える