web-dev-qa-db-ja.com

マルチスレッドC ++ 11プログラムで例外が処理されない場合はどうなりますか?

2つのスレッドを実行しているC++ 11プログラムがあり、そのうちの1つが未処理の例外をスローした場合、どうなりますか?プログラム全体が激しい死に方をするでしょうか?例外がスローされたスレッドは単独で停止しますか(その場合、この場合、例外を取得できますか)?他に完全に何か?

59

実際には何も変わっていません。 n3290の表現は次のとおりです。

一致するハンドラーが見つからない場合、関数std::terminate()が呼び出されます

terminateの動作はset_terminateでカスタマイズできますが、

必須の動作terminate_handlerは、呼び出し元に戻らずにプログラムの実行を終了します。

そのため、このような場合、プログラムは終了し、他のスレッドは実行を継続できません。

48
Ben Voigt

例外の伝播には正当な関心があるようで、これは少なくとも多少は問題に関連しているため、ここに私の提案を示します。std::threadは、構築するのに安全でないプリミティブと見なされます。より高いレベルの抽象化。それらはdoubly例外的に危険です:起動したばかりのスレッド内で例外が発生すると、先に示したようにすべてが爆発します。ただし、std::threadを起動したスレッドで例外が発生した場合、std::threadのデストラクタが*thisを結合または分離する必要があるため、問題が発生する可能性があります(または同等にスレッドではない)。これらの要件に違反すると、std::terminateが呼び出されます。

std::threadの危険性のコードマップ:

auto run = []
{
    // if an exception escapes here std::terminate is called
};
std::thread thread(run);

// notice that we do not detach the thread
// if an exception escapes here std::terminate is called

thread.join();
// end of scope

もちろん、起動するすべてのスレッドを単にdetachedした場合、その2番目の点で安全であると主張する人もいます。それに関する問題は、いくつかの状況ではjoinが最も賢明なことです。たとえば、クイックソートの「単純な」並列化では、サブタスクが終了するまで待機する必要があります。これらの状況では、joinは同期プリミティブ(ランデブー)として機能します。

私たちにとって幸運なことに、私が言及したより高いレベルの抽象化は存在し、標準ライブラリに付属しています。それらはstd::asyncstd::future、およびstd::packaged_taskstd::promiseおよびstd::exception_ptrです。上記と同等の例外セーフバージョン:

auto run = []() -> T // T may be void as above
{
    // may throw
    return /* some T */;
};

auto launched = std::async(run);
// launched has type std::future<T>

// may throw here; nothing bad happens

// expression has type T and may throw
// will throw whatever was originally thrown in run
launched.get();

実際、getを呼び出したスレッドでasyncを呼び出す代わりに、別のスレッドにbuckを渡すことができます。

// only one call to get allowed per std::future<T> so
// this replaces the previous call to get
auto handle = [](std::future<T> future)
{
    // get either the value returned by run
    // or the exception it threw
    future.get();
};

// std::future is move-only
std::async(handle, std::move(launched));
// we didn't name and use the return of std::async
// because we don't have to
27
Luc Danton