web-dev-qa-db-ja.com

C ++ 11:std :: threadに対してjoin()を呼び出さないとどうなりますか

下記のとおり:

void test() 
{
  std::chrono::seconds dura( 20 );
  std::this_thread::sleep_for( dura );
}

int main()
{
  std::thread th1(test);
  std::chrono::seconds dura( 5 );
  std::this_thread::sleep_for( dura );
  return 0;
}

mainは5秒後に終了しますが、まだ実行中のth1はどうなりますか?

mainで定義したth1スレッドオブジェクトがスコープ外になり、破棄されても、完了するまで実行を続けますか?

th1は、実行が終了した後に単にそこに座っていますか、それともプログラムが終了したときにクリーンアップされますか?

スレッドがmainではなく関数内で作成された場合はどうなりますか?プログラムが終了するか、関数がスコープ外になるまで、スレッドは残りますか?

スレッドである種のタイムアウト動作が必要な場合、スレッドに対してjoinを呼び出さないのが安全ですか?

29
kiki

デストラクタが呼び出されたときにスレッドをデタッチまたは参加していない場合、デストラクタは_std::terminate_を呼び出します。 ドラフトC++ 11標準 に移動すると、これを確認できます__30.3.1.3_スレッドデストラクタは言う:

Joinable()の場合、std :: terminate()を呼び出します。それ以外の場合、影響はありません。 [注:デストラクタでjoinable()スレッドを暗黙的にデタッチまたは結合すると、例外が発生した場合にのみ発生する正確さ(デタッチ)またはパフォーマンス(結合)のバグのデバッグが困難になる可能性があります。したがって、プログラマーは、スレッドがまだ結合可能である間、デストラクタが実行されないようにする必要があります。 —エンドノート]

この動作の根拠については、std :: threadを使用した (Not)で適切な要約を見つけることができます

結合可能なスレッドのデストラクタがstd :: terminateを呼び出さなければならないのはなぜですか?結局のところ、デストラクタは子スレッドと結合したり、子スレッドからデタッチしたり、スレッドをキャンセルしたりできます。つまり、f2がスローした場合に、予期しない(コードに明示的に示されていない)プログラムがフリーズするため、デストラクタに参加できません。

そして例が続き、また言う:

メインスレッドが子スレッドが起動されたスコープを離れ、子スレッドが実行を継続し、既になくなったスコープへの参照を保持する状況を危険にさらす可能性があるため、切り離すことはできません。

記事は N2802:スレッドオブジェクトのdetach-on-destructionを再考することを求める嘆願書 これは、結合可能な場合に破棄時に切り離されていた以前の提案に対する引数であり、2つの選択肢のいずれかがデッドロックにつながる可能性のある結合は、他の代替手段が今日持っているものであり、結合可能な場合は破棄時に_std::terminate_になります。

20
Shafik Yaghmour

std::thread::~thread()

*これに関連するスレッド(joinable() == true)がある場合、std::terminate()が呼び出されます

ソース: http://en.cppreference.com/w/cpp/thread/thread/~thread

つまり、このようなプログラムは、整形式でも安全でもありません。

ただし、この場合はboost::thread::~thread()detach()を呼び出すことに注意してください。 (ユーザーdypがコメントで述べたように、この動作は最近のバージョンでは非推奨です)

RAIIを使用すると、いつでもこれを回避できます。スレッドを別のクラスにラップするだけで、破棄時に望ましい動作が得られます。

C++ 11では、新しく作成されたスレッドがスコープ外になったときに何が起こるかを明示的に指定する必要があります(dtorが呼び出されます)。メインスレッドが継続していることが確実で、スレッドが「パイプライン」として機能している場合は、それらを「detach()」しても安全です。時々、WORKERスレッドが操作を完了するのを待っているときに、それらを 'join()'します。

this が示すように、プログラマーは、スレッドがまだ参加可能である間、デストラクタが実行されないようにする必要があります。

マルチスレッド戦略を指定します。この例では、std::terminate()が呼び出されます。

1
mkr