プログラムで複数のスレッドを作成しています。押すと Ctrl-C、シグナルハンドラが呼び出されます。シグナルハンドラ内に、最後にexit(0)
を配置しました。問題は、プログラムが安全に終了することもありますが、それ以外の場合は、実行時エラーが表示されることです
abort() has been called
それでは、エラーを回避するための可能な解決策は何でしょうか?
通常の方法は、すべてのスレッド(メインスレッドを含む)によってチェックされるatomicフラグ(std::atomic<bool>
など)を設定することです。設定すると、サブスレッドが終了し、メインスレッドがサブスレッドをjoin
開始します。 Thenきれいに終了できます。
スレッドにstd::thread
を使用すると、クラッシュが発生する可能性があります。 std::thread
オブジェクトを破棄する前に、スレッドをjoin
する必要があります。
他の人は、シグナルハンドラーに_std::atomic<bool>
_を設定させ、他のすべてのスレッドにその値を定期的にチェックさせて、いつ終了するかを知らせることを言及しています。
このアプローチは、他のすべてのスレッドが適切な頻度でとにかく定期的に起動している限り、うまく機能します。
ただし、1つ以上のスレッドが純粋にイベント駆動型である場合、完全に満足できるものではありません。ただし、イベント駆動型プログラムでは、スレッドは、実行する作業がある場合にのみ起動することになっています。一度に数日または数週間眠ります。単にアトミックブールフラグをポーリングするために(非常に多く)ミリ秒ごとにウェイクアップするように強制された場合、これにより、非常にCPU効率の高いプログラムのCPU効率が大幅に低下します。 24時間365日。これは、CPUが省電力モードに移行するのを妨げる可能性があるため、バッテリー寿命を節約しようとする場合、特に問題になる可能性があります。
ポーリングを回避する別のアプローチは次のとおりです。
select()
fd_setに含める(またはpoll()
またはその他の待機のために同様のアクションを実行させる)スレッドがブロックするIO関数)select()
呼び出しがすぐに戻り、FD_ISSET(receivingSocket)
は受信したバイトのためにtrueを示します。join()
を呼び出す必要があります。これにより、すべての子スレッドが実際になくなったことを保証できますbeforemain()は戻ります。 (これは、競合状態のリスクがあるために必要です-たとえば、post-main()クリーンアップコードは、まだ実行中の子スレッドがリソースを使用しているときにリソースを解放し、クラッシュにつながる場合があります)最初に受け入れる必要があるのは、スレッド化が難しいということです。
「スレッドを使用するプログラム」は「メモリを使用するプログラム」とほぼ同じくらい一般的であり、あなたの質問は「メモリを使用するプログラムでメモリを破損しない方法」に似ています。
スレッドの問題を処理する方法は、スレッドの使用方法とスレッドの動作を制限することです。
スレッドシステムがデータフローネットワークに組み込まれた小さな操作の束である場合、操作が大きすぎる場合は小さな操作に分割され、システムでチェックポイントを実行するという暗黙の保証により、シャットダウンは非常に異なるように見えます外部のDLLをロードして、1秒から10時間まで無限の長さで実行するスレッドがある場合よりも。
C++のほとんどのものと同様に、問題の解決は、所有権、制御、および(最後の手段として)ハッキングに関するものです。
C++のデータと同様に、すべてのスレッドを所有する必要があります。スレッドの所有者は、そのスレッドを大幅に制御し、アプリケーションがシャットダウンしていることを通知できる必要があります。シャットダウンメカニズムは堅牢でテスト済みで、理想的には他のメカニズム(投機的タスクの早期中止など)に接続する必要があります。
Exit(0)を呼び出しているという事実は悪い兆候です。 main実行スレッドにクリーンなシャットダウンパスがないことを意味します。そこから始めましょう。割り込みハンドラーは、シャットダウンを開始するスレッドをmainに通知し、メインスレッドを正常にシャットダウンする必要があります。すべてのスタックフレームを巻き戻し、データをクリーンアップする必要があります。
次に、クリーンで高速なシャットダウンを可能にする同じ種類のロジックを、スレッド化されたコードにも適用する必要があります。
条件変数/アトミックブール値と同じくらい簡単だとあなたが言っている人は誰でも、ポーリングはあなたに手形を売っています。運がよければ簡単な場合にのみ機能し、確実に機能するかどうかを判断するのは非常に困難です。
一部のプログラマーの回答に加えて、コメントセクションの説明に関連して、スレッドの終了をatomic
タイプとして制御するフラグを作成する必要があります。
次の場合を検討してください。
bool done = false;
void pending_thread()
{
while(!done)
{
std::this_thread::sleep(std::milliseconds(1));
}
// do something that depends on working thread results
}
void worker_thread()
{
//do something for pending thread
done = true;
}
ここで、ワーカースレッドはmain
スレッドにすることもでき、done
はスレッドのフラグを終了しますが、保留中のスレッドは、終了する前に作業スレッドによって特定のデータを処理する必要があります。
この例には、競合状態と未定義の動作があり、実際の問題を実際に見つけるのは非常に困難です。
std::automic
を使用した修正バージョン:
std::atomic<bool> done(false);
void pending_thread()
{
while(!done.load())
{
std::this_thread::sleep(std::milliseconds(1));
}
// do something that depends on working thread results
}
void worker_thread()
{
//do something for pending thread
done = true;
}
競合状態やUBを気にせずにスレッドを終了できます。