4

ワーカースレッドが作業を行うための条件を待機している出口ハンドラースレッドがあります。シグナリングは、ワーカースレッドのデストラクタから行われます。

以下は、出口ハンドラスレッドのコードです。

void Class::TaskExitHandler::run() throw()
{

while( ! isInterrupted() ) {

    _book->_eot_cond.wait(); // Waiting on this condition
    {
        CLASS_NAMESPACE::Guard<CLASS_NAMESPACE::FastLock> eguard(_book->_exitlist_lock);

        list<TaskGroupExecutor*>::const_iterator itr = _book->_exited_tasks.begin();

        for( ; itr != _book->_exited_tasks.end(); itr++ ) {
            (*itr)->join();
            TRACER(TRC_DEBUG)<< "Deleting exited task:" << (*itr)->getLoc() << ":"
                     << (*itr)->getTestID() << ":" << (*itr)->getReportName() << endl;
            delete (*itr);
        }
        _book->_exited_tasks.clear();
    }
    _book->executeAny();
}
}
}

ここで、ワーカースレッドが(下位層から発生した)例外をキャッチすると、このスレッドは続行され、すぐに終了コード134(SIGABRT)でコアリングされることが確認されています。

スタックトレースは次のとおりです-

#0  0x0000005555f49b4c in raise () from /lib64/libc.so.6
#1  0x0000005555f4b568 in abort () from /lib64/libc.so.6
#2  0x0000005555d848b4 in __gnu_cxx::__verbose_terminate_handler () from /usr/lib64/libstdc++.so.6
#3  0x0000005555d82210 in ?? () from /usr/lib64/libstdc++.so.6
#4  0x0000005555d82258 in std::terminate () from /usr/lib64/libstdc++.so.6
#5  0x0000005555d82278 in ?? () from /usr/lib64/libstdc++.so.6
#6  0x0000005555d81b18 in __cxa_call_unexpected () from /usr/lib64/libstdc++.so.6
#7  0x0000000120047898 in Class::TaskExitHandler::run ()
#8  0x000000012001cd38 in commutil::ThreadBase::thread_proxy ()
#9  0x0000005555c6e438 in start_thread () from /lib64/libpthread.so.0
#10 0x0000005555feed6c in __thread_start () from /lib64/libc.so.6
Backtrace stopped: frame did not save the PC

したがって、「throw()」仕様を使用して例外をスローしないことを指定するこのrun()関数は、(フレーム4から)例外を発生させるようです。__cxa_call_unexpected()に関するさまざまな参照に従って、スタックトレースは、「throw()」仕様の関数で例外が発生したときに中止するコンパイラの一般的な動作を示しています。問題の分析は正しいですか?

テストするために、このメソッドにtry catchを追加し、例外メッセージを出力しました。今、プロセスはコアではありませんでした。例外メッセージは、ワーカースレッドによってキャッチされたものと同じでした。私の質問は、このスレッドが他のスレッドによってキャッチされた例外にどのようにアクセスできるかということです。それらは、例外処理に関連するいくつかのデータ構造を共有していますか?

これに少し光を当ててください。かなり不可解です。

注:-stacktraceに従って、run()が呼び出された直後にcall_unexpectedが発生します。それは、どういうわけか例外スタックまたはデータが共有されているという私の疑問を強めます。しかし、この振る舞いへの言及は見つかりませんでした。

4

2 に答える 2

1

私自身の質問に答えます。この場合に起こったことは、TaskExitHandlerスレッドで呼び出されているデストラクタがあったことです。このデストラクタは、メインスレッドで例外を引き起こしたのと同じ操作を実行していました。

TaskExitHandlerスレッドはスローしないように(または期待されるように)設計されていたため、try-catchブロックがなかったため、例外が発生したときにプロセスが中止されました。

デストラクタの呼び出しは暗黙的であったため、スタックトレースに表示されることはなく、見つけるのが非常に困難でした。この例外リークを見つけるには、各オブジェクトを追跡する必要がありました。

積極的に参加してくれた皆さんに感謝します:)これはいくつかの積極的な回答を得るための私の最初の質問でした。

于 2012-05-03T10:03:35.870 に答える
0

私は刺します-うまくいけば、これはあなたの研究を続けるのに十分なものになるでしょう。

TaskExitHandlerを実行しているスレッドが、すべてのワーカースレッドの親スレッドであると思われます。そうでなければ、TEHは子供たちと一緒に参加するのに苦労するでしょう。

子/ワーカースレッドは、スローされた例外を処理していません。ただし、例外はどこかで処理する必要があります。そうしないと、プロセス全体がシャットダウンされます。親スレッド(別名TEH)は、例外を処理するためのプロセスのスタック/チェーンの最後の停止です。サンプルコードは、TEHの例外処理が単に例外をスローする/処理しないことであることを示しています。だからそれはコアアウトします。

共有されているのは必ずしもデータ構造ではなく、プロセス/スレッドIDとメモリスペースです。子スレッドはグローバルメモリ/ヒープスペースを親と相互に共有するため、ロックのためにセマフォやミューテックスが必要になります。

適切なカプセル化は、ワーカースレッドが発生する可能性のあるすべての例外を処理するのに十分スマートである必要があることを示します。そうすれば、親スレッドと残りのプロセスツリーを停止する代わりに、個々のワーカースレッドを強制終了できます。OTW、TEHで例外をキャッチし続けることはできますが、スレッドが例外をどう処理するかについての知識を持っている(または持っているべきである)可能性はほとんどありません。

上記が明確でない場合はコメントを追加してください。さらに説明させていただきます。

少し調べて、例外がスタックメモリではなくヒープメモリに対して生成されることを確認しました。プロセスのすべてのスレッドが同じヒープ*を共有するため、子スレッドが例外をキャッチしない場合に親スレッドが例外を認識する理由は(少なくとも私にとっては)より理にかなっています。* FWIW、新しいスレッドを開始する代わりにプロセスをフォークすると、新しいヒープも取得されます。ただし、すべてのヒープコンテンツを新しいプロセスにもコピーするため、フォークはメモリに対するコストのかかる操作です。

このSOスレッドでは、すべての例外をキャッチするためのスレッドの設定について説明します。これはおそらく興味深いものです。 別のスレッドからの例外をキャッチすることです。

于 2012-05-01T18:06:26.450 に答える