web-dev-qa-db-ja.com

std :: quick_exitとstd :: abortの違いは何ですか?また、なぜstd :: quick_exitが必要だったのですか?

C++ 11では、プログラムの実行を終了する新しい方法_std::quick_exit_が導入されています。

N3242 18.5(p。461)の引用:

_[[noreturn]] void quick_exit(int status) noexcept;
_

効果:_at_quick_exit_の呼び出しによって登録された関数は、登録の逆の順序で呼び出されます。ただし、関数は、登録時にすでに呼び出されていた以前に登録された関数の後に呼び出されます。 _quick_exit_を呼び出した結果としてオブジェクトが破棄されてはなりません。関数がスローされた例外のハンドラーを提供しないために、コントロールが_quick_exit_によって呼び出される登録済み関数を離れる場合、terminate()が呼び出されます。 [注:_at_quick_exit_は、登録された関数を、それを登録したスレッドとは異なるスレッドから呼び出す可能性があるため、登録された関数は、スレッドの保存期間を持つオブジェクトのIDに依存しないでください。 — end note]登録された関数を呼び出した後、_quick_exit_は_Exit(status)を呼び出すものとします。 [注:標準のファイルバッファーはフラッシュされません。 ISO C7.20.4.4を参照してください。 —エンドノート]

std::abort(void)std::_Exit(int status)の定義は、ステータスを親プロセスに渡す機能のみが異なるため、私の疑問が生じます。

_std::quick_exit_と_std::abort_のセマンティクスの唯一の違いは、_std::quick_exit_が_std::at_quick_exit_を使用して登録された関数を呼び出し、返されるステータスを設定できることを意味しますか?

この機能を導入した理由は何でしたか?

41
Rafał Rawicki

良い記事があります ここで入手可能 、私はそれを要約します。この機能は、スレッドを使用するときにプログラムをクリーンに終了することの難しさに特に対処するために追加されました。本質的に、終了は高度に非同期のイベント、ユーザーがユーザーインターフェースを閉じる、管理者がマシンをシャットダウンするなどによって開始されます。これは、プログラムが開始したスレッドの状態に関係なく発生し、ほとんどの場合、非常に予測不可能な状態にあります。

理想的な世界では、プログラムのmain()関数は、通常はイベントを通知することにより、スレッドに終了を要求し、スレッドが終了するのを待ってから、exit()によるクリーンシャットダウンのためにmain()を終了します。ただし、その理想は非常に達成するのが困難です。たとえば、I/Oが完了するのを待つなど、スレッドがシステムコールの奥深くに埋め込まれる可能性があります。または、別のスレッドから正しい順序で通知される必要がある同期オブジェクトをブロックしています。結果が快適になることはめったになく、実際のプログラムは終了時にデッドロックすることがよくあります。または、シャットダウンの順序が予期しない場合にクラッシュします。

この問題には、単純で非常に魅力的な回避策があります。代わりに_exit()を呼び出します。 Kaboom、プログラムは終了し、オペレーティングシステムは榴散弾を箒します。しかし、明らかにクリーンアップがまったく行われず、ファイルの半分が書き込まれたり、dbaseトランザクションが不完全だったりするなどのアーティファクトが発生することがあります。

std :: quick_exit()は代替手段を提供します。 _exit()に似ていますが、at_quick_exitに登録されているものは何でも、コードを実行するオプションがあります。

40
Hans Passant

std::quick_exitの理論的根拠は、 N1327 および N244 で説明されています。 quick_exit_Exit、およびexitの主な違いは、静的デストラクタの処理と重要な情報の安定したストレージへのフラッシュに関するものです。

  • std::_Exit:静的デストラクタを実行したり、重要なIOをフラッシュしたりしません。
  • std::exit:静的デストラクタを実行し、重要なIOをフラッシュします。
  • std::quick_exit:静的デストラクタを実行しませんが、重要なIOをフラッシュします。

(前述のように、std::abortSIGABRTを送信するだけです。)

23
一二三

std::abortは、「at_exit/at_quick_exit」を使用して登録された関数を呼び出さずにアプリケーションを終了します。一方、std::quick_exitは、ご指摘のとおり、std::at_quick_exitを使用して登録された関数を呼び出します。

std::abort通常abortsアプリケーション。これは、異常な状況が発生し、クリーンアップを行わずにアプリケーションを閉じる必要がある場合に呼び出す必要があります。 std::abortドキュメントから:

SIGABRTがシグナルに渡されたシグナルハンドラーによってキャッチされ、ハンドラーが戻らない場合を除いて、プログラムの異常終了を引き起こします。

クリーンアップを実行する場合は、std::quick_exitがより適切になります。この最後の関数を使用すると、アプリケーションを正常に停止することもできます。これは、std::_Exitのようなシグナル(SIGABRTにシグナルを送信し、アプリケーションを異常に停止させる)の代わりにstd::abortを呼び出すことになるためです。

std::exitを使用すると、自動スレッドローカル変数と静的変数をクリーンアップしながら、アプリケーションを正常に終了できます。 std::quick_exitはしません。そのため、名前に「quick_」が含まれています。クリーンアップフェーズをスキップするため、高速です。

したがって、両方の機能の間に実際の意味上の違いがあります。 1つはアプリケーションを異常に停止し、もう1つはグレースフル終了を実行して、いくつかのクリーンアップを実行できるようにします。

2
mfontanini