1. ホーム
  2. c++

[解決済み] main()が終了したとき、デタッチド・スレッドはどうなるのでしょうか?

2022-04-29 23:29:57

質問

を始めると仮定します。 std::thread で、次に detach() を含むので、スレッドが実行され続けます。 std::thread を表現していたものが、スコープ外に出てしまったのです。

さらに、プログラムが切り離されたスレッドに参加するための信頼できるプロトコルを持っていないと仮定します。 1 のとき、切り離されたスレッドはまだ実行されています。 main() が終了します。

標準規格(正確には N3797 C++14 ドラフト)の 1.10 と 30.3 のいずれにも適切な文言が含まれておらず、どのようなことが起こるべきかを記述したものが見当たりません。

1 なぜなら、参加するためにどのようなプロトコルを発明するにしても、シグナリング部分はスレッドがまだ動作している間に行われなければならず、OSスケジューラはシグナリングが行われた直後にスレッドを1時間スリープさせることを決定し、受信側がスレッドが実際に終了したことを確実に検出する方法はないからです。

を使い切った場合 main() は未定義な動作です。 任意の の使用 std::thread::detach() は、メインスレッドが決して終了しない限り、未定義の動作です。 2 .

を使い果たすと main() デタッチド・スレッドが動作している状態では 定義された の効果があります。という質問があります。 どこ (は、(その中の C++標準 POSIXでもOSのドキュメントでもなく...)で定義されている効果です。

2 切り離されたスレッドを結合することはできません( std::thread::join() ). あなたは できる からのfutureを経由して)分離されたスレッドからの結果を待ちます。 std::packaged_task しかし、これは の実行を終了しています。 . 実際、スレッドの最初の自動オブジェクトのデストラクタにシグナリングの部分を入れない限り、そこに 意志 を実行するコード(デストラクタ)が存在します。 信号のコード。もしOSがメインスレッドが結果を消費し、デタッチドスレッドが前記デストラクタの実行を終える前に終了するようスケジュールした場合、何が起こるか^Wisは定義されていますか?

解決方法は?

元の質問に対する答えは、「切り離されたスレッドは、次のような場合にどうなるのか」というものです。 main() exits" です。

他のスレッドの(自動|thread_local)変数や静的オブジェクトに触れない限り、 (標準では停止しているとは書かれていないので)それは走り続け、 それはうまく定義されています。

これは、スレッドマネージャーを静的オブジェクトとして許可しているようです(註 [基本.開始.項]/4 にはそのように書かれています。ポインタをくれた @dyp に感謝します)。

静的オブジェクトの破壊が終了すると、シグナルハンドラで許可されたコードのみが実行できる体制に入るため、問題が発生します ( [基本.開始.項]/1、第1文 ). C++の標準ライブラリのうち、それだけが <atomic> ライブラリ( [サポート.ランタイム]/9、第2文 ). 特に、一般的に を除きます。 condition_variable (の一部ではないので、シグナルハンドラで使用するために保存されるかどうかは実装で決まります)。 <atomic> ).

この時点でスタックを解放していなければ、未定義の動作を回避する方法はわかりません。

2つ目の質問「切り離されたスレッドを再び結合することは可能か」に対する答えは、次のとおりです。

はい。 *_at_thread_exit 関数群 ( notify_all_at_thread_exit() , std::promise::set_value_at_thread_exit() , ...).

質問の脚注[2]にあるように、条件変数やセマフォやアトミックカウンターをシグナリングすることは、(その実行の終了を保証するという意味で)切り離されたスレッドを結合するには十分ではありません。 ハッシュハップンビフォー の後に実行されるコードが多くなるため、待機中のスレッドがそのシグナルを受け取ることができない。 notify_all() 特に、自動的なオブジェクトやスレッドローカルなオブジェクトのデストラクタがそうである。

スレッドが最後に行うこととしてシグナルを実行する ( 自動生成オブジェクトとスレッドローカルオブジェクトのデストラクタ ハプニング ) は、どのような _at_thread_exit は、そのために設計された関数群です。

したがって、標準が要求する以上の実装保証がない場合に未定義の動作を避けるためには、切り離されたスレッドを(手動で) _at_thread_exit 関数がシグナル伝達を行う または 切り離されたスレッドに実行させる のみ のコードも、シグナルハンドラとしては安全でしょう。