1

起動時にスレッドを作成するプログラムがあります (スレッドを作成するために C++ Boost ライブラリを使用しています)。メインプログラムでは、クリーンアップ関数を次のように登録しました。

atexit(cleanExit)
// Trap some signals for a clean exit.
signal(SIGQUIT, signalled)
signal(SIGABRT, signalled)
signal(SIGTERM, signalled)
signal(SIGINT, signalled)

static void signalled(int signal)
{
    exit(signal)
}
static void cleanExit(void)
{
     thread->interrupt();
     thread->join();
}

上記のように、クリーン終了プロセス中にスレッドを中断し、ここで (メイン プロセスで) 待機して、スレッドがクリーンアップ処理を実行するようにします。thread->interrupt を呼び出すと、スレッドが中断され、スレッドのクリーンアップを行います。ここまではすべてがスムーズに機能しており、問題はありません。

しかし、スレッドでクリーンアップ関数を呼び出すと問題が発生します。クリーンアップ関数では、いくつかのステータスをサーバーに送り返しています。そのために、ユーティリティ関数を作成しました。このユーティリティ関数では、クラスの「const static string」メンバーにアクセスしています。問題は、この const 静的文字列にアクセスすると、アプリケーションがスタックしてしまうことです。strace で確認したところ、Seg Fault が発生しています。しかし、この「const static string」を「const string」に変更すると、クリーンアップがスムーズになります。

質問 プログラムが終了すると、C++ の「const static」の動作はどうなりますか。exit が呼び出されたときに諦めますか (上記のケースで見られます)、またはこの動作に関する考えはありますか。


更新 # 1

これがスレッドハンドラ関数です。上で述べたように、Boost スレッドです。

try {
    while ( true ) {
        // Do your job here.
        // 1: We can be interrupted.
        boost::this_thread::interruption_point();
    }
}
catch (boost::thread_interrupted const& )
{
    // Before exiting we need to process all request messages in the queue
    completeAllWorkBeforeExiting();
}

メイン プログラムが thread->interrupt を呼び出すと、スレッドは # 1 で thread_interrupted 例外を発生させ、この例外をキャッチしてクリーンアップ作業を行っています。

4

1 に答える 1

2

constオブジェクトが破棄された場合には影響しません。

staticオブジェクトは、作成された順序とは逆の順序で破棄されます。基本的に、指定された関数をデストラクタとしてatexit無名オブジェクトを作成します。staticつまり、staticオブジェクトのデストラクタとatexitコールバックは、それらの構築/登録と逆の順序で発生します。

exitシグナルハンドラから呼び出すのは完全に安全ではありません。シグナルハンドラが実際にできることは、後でスレッドによってポーリングされるフラグを設定することだけです。あなたが言及したように、シグナルハンドラは割り込み時に実行されるため、システムコールを中断する可能性があります。再入可能性は同じスレッド上にあり、通常発生する別のスレッド上にないため、 のマルチスレッド ロックmallocをバイパスするような方法で中断する可能性があります。malloc

これが、あらゆる種類の予測不可能な動作の原因となります。詳細を確認しないと、どのような効果があるかをより具体的に示すことはできませんがstatic、オブジェクトの有効期間を変更したり、オブジェクトごとに 1 回インスタンス化したりすることに関係があると思われます。

于 2013-01-09T08:14:47.270 に答える