1

可能な限り多くの終了の原因となるイベントをカバーして、プロセスが終了する理由についてログに記録したり、処理したり、その他の方法で手がかりを残したりする方法はありますか?

私は自分のアプリケーション用のログツールを持っており、毎分多くのメッセージをログに記録します。プログラムのほぼ全体をスーパーtry-catchブロックで実行しているので、未処理の例外をログに記録できます。また、最近、プロセスを終了する可能性のあるさまざまなプロセス信号のハンドラーを登録しようとしました。ただし、アプリケーションはまだ1日に数回クラッシュしており、その理由はわかりません。

ログに記録または処理できなかった他の致命的なイベントはいくつありますか?私がまだ気付いていない新しいタイプのイベントのためにプロセスが停止したときに、常に暗闇に置かれるのではなく、これを行う適切な方法があることを期待しています。

どうもありがとう。

4

5 に答える 5

2

スーパーtry/catchブロックがあるということは、キャッチ可能な例外が処理されないことを意味します。開始されたすべてのスレッドにこれらのブロックが必要になることに注意してください。

signalそれはさておき、終了信号をキャッチするために使用できます。これらは:

  • SIGABRT(Signal Abort)アボート機能によって開始されるなどの異常終了。
  • SIGFPE(Signal Floating-Point Exception)ゼロ除算やオーバーフローを引き起こす演算(必ずしも浮動小数点演算ではない)などの誤った算術演算。
  • SIGILL(Signal Illegal Instruction)不正な命令など、無効な関数イメージ。これは通常、コードの破損またはデータの実行の試みが原因です。
  • SIGINT(信号割り込み)インタラクティブな注意信号。通常、アプリケーションユーザーによって生成されます。
  • SIGSEGV(Signal Segmentation Violation)ストレージへの無効なアクセス:プログラムがメモリの外部で読み取りまたは書き込みを行おうとすると、プログラムに割り当てられます。SIGTERM(Signal Terminate)プログラムに送信された終了要求。
  • 実装によって定義されたシグナルですが、ほとんどのクラッシュの原因はこれらによってカバーされるべきです。

また、プログラムがクラッシュしていない可能性がありますが、mainから戻るか(ただし、すでにカバーされていると思います)、またはへの呼び出しによって終了しますexit。その場合、プログラムの戻り値を確認してログに記録できます。

于 2012-04-11T22:19:38.163 に答える
2

予期しない例外を処理する関数を登録できます。

set_unexpected()

そうでない場合は、アプリケーションがterminat()を呼び出します。

終了時にログを記録する関数を登録できます。

set_terminate()

処理を実行する独自のatexit()ロギング関数を追加できます(終了が異常に発生した場合にのみ処理を実行するようにフラグを設定し、メインを離れる直前にフラグを設定します)。

シグナルハンドラーは扱いにくい場合があります(特にポータブルにしたい場合)。それらを使用する場合、内部で安全に実行できることには制限があるため、通常はグローバルフラグを設定して、通常のコードで処理できるようにします(もちろん、終了する場合は非常に制限されます)。

于 2012-04-11T22:40:46.957 に答える
2

これが私のプログラムで使用しているものです、それは私のために働きます....私のプログラムがクラッシュするたびに、クラッシュサイトのスタックトレースをstdoutに出力します(おそらくファイルなどにリダイレクトされ、後で読むことができます)。

スタックトレースに人間が読み取れる関数名が含まれていることを確認するために、MakefileのCXXFLAGSやLFLAGSのフラグとして-rdynamicを渡す必要がある場合があることに注意してください。

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

void PrintStackTrace()
{
   void *array[256];
   size_t size = backtrace(array, 256);
   char ** strings = backtrace_symbols(array, 256);
   if (strings)
   {
      printf("--Stack trace follows (%zd frames):\n", size);
      for (size_t i = 0; i < size; i++) printf("  %s\n", strings[i]);
      printf("--End Stack trace\n");
      free(strings);
   }
   else printf("PrintStackTrace:  Error, could not generate stack trace!\n");
}

static void CrashSignalHandler(int sig)
{
   // Uninstall this handler, to avoid the possibility of an infinite regress
   signal(SIGSEGV, SIG_DFL);
   signal(SIGBUS,  SIG_DFL);
   signal(SIGILL,  SIG_DFL);
   signal(SIGABRT, SIG_DFL);
   signal(SIGFPE,  SIG_DFL);

   printf("CrashSignalHandler called with signal %i... I'm going to print a stack trace, then kill the process.\n", sig);
   PrintStackTrace();
   printf("Crashed process aborting now.... bye!\n");
   fflush(stdout);
   abort();
}

int main(int argc, char ** argv)
{
   signal(SIGSEGV, CrashSignalHandler);
   signal(SIGBUS,  CrashSignalHandler);
   signal(SIGILL,  CrashSignalHandler);
   signal(SIGABRT, CrashSignalHandler);
   signal(SIGFPE,  CrashSignalHandler);

   [...remainder of your program goes here...]
}
于 2012-04-12T06:46:27.347 に答える
0

1つのコードは多くの言葉の価値があります:

#include <iostream>
#include <signal.h>

sigint_handler(int s) {
    std::cout<<"signal caught: "<<s<<std::endl;
    ::exit(-1);
}

void setup_signal() {
    struct sigaction sigIntHandler;
    sigIntHandler.sa_handler = sigint_handler;
    sigemptyset(&sigIntHandler.sa_mask);
    sigIntHandler.sa_flags = 0;
    sigaction(SIGINT, &sigIntHandler, NULL);
    sigaction(SIGTERM, &sigIntHandler, NULL);
}

int main() {
    setup_signal();
    /* do stuff */
    return 0;
}

もちろん、これはSIGINT/SIGTERMシグナルのみを処理します。また、このコードをすべてのatexit()、set_terminate、super try/catchなどで更新する必要があります。そして、あなたがsegfaults/バスエラー/何でも遭遇した場合に備えて...まああなたは運命にあります:)

于 2012-04-11T22:40:49.253 に答える
0

この質問をチェックしてください。 UNIXでログファイルなしでプロセスが停止した理由を見つける方法は?

ここで、bashを使用してプロセスの終了コードを取得する方が、シグナルハンドラーや任意の種類の終了コールバックを使用するよりもはるかに簡単であることがわかります。

于 2012-04-12T06:29:14.943 に答える