web-dev-qa-db-ja.com

LinuxCが正常終了のためにkillシグナルをキャッチ

ソケットやデータベース接続などを使用するプロセスがあります。これは基本的に、センサーデータとWebインターフェイスの間を中継するサーバープロセスであるため、アプリケーションが強制終了された場合に正常に終了するようにすることが重要です。

セグメンテーション違反(少なくともデバッグ用)やkillシグナルなどの予期しない例外を処理して、接続を閉じ、実行中のスレッドを停止して、プロセスが使用しているものを混乱させないようにするにはどうすればよいですか?

16
user623879

シグナルハンドラーをインストールしてシグナルをキャッチしますが、99%の場合、終了してLinux OSにクリーンアップを任せたいだけです。これにより、すべてのファイル、ソケット、空きメモリ、シャットダウンスレッドが正常に閉じられます。

したがって、ソケットでメッセージを送信するなど、特に実行したいことがない限り、プロセスを終了して、シグナルをキャッチしようとしないでください。

9
Soren

信号をキャッチするのは難しいです。あなたは注意する必要があります。最初のステップは、sigactionを使用して、目的の信号の信号ハンドラーをインストールすることです。

  • 応答するシグナルのセットを選択し、それらがプロセスにとって何を意味するかを選択します。たとえば、SIGTERMが終了し、SIGHUPが再起動し、SIGUSR1設定などをリロードします。

  • すべてのシグナルに応答しようとしないでください。また、プログラムのエラーを示すシグナルの後に「クリーンアップ」しようとしないでください。 SIGKILLをキャッチできません。 SIGSEGVSIGBUS、およびそれらのような他のものは、非常に正当な理由がない限り、捕まえられるべきではありません。デバッグする場合は、コアダンプの上限を引き上げます。デバッガーをコアイメージにアタッチすることは、あなたや私がこれまでにコーディングしたものよりもはるかに効果的です。 (SIGSEGVなどの後でクリーンアップしようとすると、クリーンアップコードによって追加のSIGSEGVが発生し、状況がすぐに悪化する可能性があることに注意してください。混乱を避けて、 SIGSEGVプログラムを終了します。)

  • 信号の処理方法には注意が必要です。アプリケーションにメインループ(例:selectまたはpoll)がある場合、シグナルハンドラーはフラグを設定するか、特別なパイプにバイトを書き込んで、メインループを終了するように通知できます。 siglongjmpを使用してシグナルハンドラーからジャンプすることもできますが、これを正しく行うのは非常に難しく、通常は必要なものではありません。

アプリケーションがどのように構成され、何をするのかを知らずに何かを推奨するのは難しいです。

また、シグナルハンドラ自体はほとんど何もしないはずです。多くの関数は、シグナルハンドラーから呼び出すのは安全ではありません。

12
Dietrich Epp

私は時々SIGSEGVのバックトレースを取得したいのですが、キャッチ部分は次のようになります。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void sig_handler(int);

int main() {
    signal(SIGSEGV, sig_handler);
    int *p = NULL;
    return *p;
}

void sig_handler(int sig) {
    switch (sig) {
    case SIGSEGV:
        fprintf(stderr, "give out a backtrace or something...\n");
        abort();
    default:
        fprintf(stderr, "wasn't expecting that!\n");
        abort();
    }
}

あなたはこれらのものを非常に注意深く扱うことを望みます、例えば。別の信号をトリガーできないことを確認してください。

7
daniel