2

FreeGLUT を使用して、Linux でマルチスレッド C++ アプリケーションに取り組んでいます。奇妙なことに、スレッドの 1 つで exit() を呼び出すと、onexit() コールバックが呼び出されて完了しますが、プログラムを終了できません。GDB によると、代わりに GLUT ライブラリの select() 呼び出しでハングします。

「q」を押すと終了するキーボード コールバックもあります。プログラムがハングしているときに「q」を押すと、GLUT は問題なく終了します。

誰も同じような問題を抱えているようには見えません。ドキュメンテーションによると、 exit() はスレッドだけでなくプロセス全体を閉じることになっているため、そうではありません。私は困惑しています。あなたはなにか考えはありますか?

編集:問題が見つかりました。終了ハンドラーが終了したのは間違いでした。ライブラリ関数呼び出しは、exit() が呼び出された時点で既にロックされているミューテックスで待機していました。GLUTは自由時間を利用しただけです。ご回答ありがとうございます。

4

1 に答える 1

3

C++03 の場合

注: exit() は C 関数です。

言語としての C には、言語レベルでのスレッドの概念がありません。
スレッドは通常、ライブラリ サポートを介して C に追加されます。そのため、メイン スレッドではないスレッドから exit() を呼び出した場合の影響については、ライブラリのドキュメントを読む必要があります。

おそらく、スレッド化の実装間での移植性はありません。

あなたの最善の策は、メインスレッドからのみ exit() を呼び出すことです。
子スレッドでは、おそらくメイン スレッドによって表示される状態を設定する必要があります。メイン スレッドにこの状態を認識させ、手動で exit を呼び出します。man スレッドで exit を呼び出しても、子スレッドがまだ実行されている場合、一部のスレッド ライブラリがハングする可能性があることに注意してください。したがって、コードを移植可能にしたい場合は、終了する前にメインスレッドがすべての子を待機するようにするのが最善です。

C++11 の場合

C++11 が登場した今、言語の明示的なスレッド化により、さらに多くのことが行われています。See n3376 Section 18.4.1 [cstdint.syn] Paragraph 8

この国際標準では、関数 exit() には追加の動作があります。

— まず、スレッド保存期間があり、現在のスレッドに関連付けられているオブジェクトが破棄されます。次に、静的な保存期間を持つオブジェクトが破棄され、atexit を呼び出して登録された関数が呼び出されます。

      See 3.6.3 for the order of destructions and calls. (Automatic objects are not destroyed as a result of calling exit().)

      If control leaves a registered function called by exit because the function does not provide a handler for a thrown exception, std::terminate() shall be called (15.5.1).

— 次に、バッファリングされたデータが書き込まれていないすべての開いている C ストリーム (で宣言されている関数シグネチャによって仲介される) がフラッシュされ、開いているすべての C ストリームが閉じられ、tmpfile() の呼び出しによって作成されたすべてのファイルが削除されます。

— 最後に、制御がホスト環境に戻されます。status が 0 または EXIT_SUCCESS の場合、成功した終了ステータスの実装定義形式が返されます。ステータスが EXIT_FAILURE の場合、ステータスの失敗した終了の実装定義形式が返されます。それ以外の場合、返されるステータスは実装定義です。

于 2012-07-10T02:48:59.930 に答える