2010-11-22 34 views

答えて

24

デフォルトでは、ほとんどの信号は、プログラムの即時の異常終了を引き起こします。

しかし、ほとんどの信号のデフォルト動作を簡単に変更できます。あなたはこのプログラムとプレスコントロール-Cを実行する場合

#include <iostream> 
#include <signal.h> 
#include <unistd.h> 
#include <cstring> 
#include <atomic> 

std::atomic<bool> quit(false); // signal flag 

void got_signal(int) 
{ 
    quit.store(true); 
} 

class Foo 
{ 
public: 
    ~Foo() { std::cout << "destructor\n"; } 
}; 

int main(void) 
{ 
    struct sigaction sa; 
    memset(&sa, 0, sizeof(sa)); 
    sa.sa_handler = got_signal; 
    sigfillset(&sa.sa_mask); 
    sigaction(SIGINT,&sa,NULL); 

    Foo foo; // needs destruction before exit 
    while (true) 
    { 
     // do real work here... 
     sleep(1); 
     if(quit.load()) break; // exit normally after SIGINT 
    } 
    return 0; 
} 

は、あなたが単語「デストラクタ」を参照してくださいする必要があります

このコードは、すべての通常のデストラクタを呼び出すなど、通常は信号出口プログラムを作成する方法を示しています印刷されます。シグナルハンドラ関数(got_signal)は、実際にあなたが何をしているのか分からない限り、フラッグを設定して静かに戻す以外にはめったに何もするべきではないことに注意してください。

ほとんどのシグナルは上に示したようにキャッチ可能ですが、SIGKILLではなく、制御できません。SIGKILLは暴走プロセスを強制終了する最後の方法であり、ユーザーがプロセスを凍結させるSIGSTOPではないからです。必要に応じてSIGTSTP(control-Z)をキャッチすることができますが、シグナルに関心があるのはデストラクタの振る舞いである必要はありません。最終的には制御-Zの後にプロセスが起動し、実行を継続し、すべてのデストラクタを有効にして正常に終了します。

+5

IIRCの場合、 'quit'の正しい型は' volatile std :: sig_atomic_t'です。その目的のために 'bool'を使うのはUBです。 – MSalters

+0

@MSalters:そうです、sigaction()の前にsigfillset()呼び出しを含めるべきでしょう。おそらくsig_atomic_tよりも優れています。ブールを使用することは、信号ハンドラの中断を防ぐために追加の信号がブロックされている場合には、より慣れており、完全に安全です。サンプルコードを編集しました。ありがとうございます。 –

+2

私は実際に、このコードで 'quit = false'行に' '削除された関数の使用' 'というエラーを受け取ります。 'quit = false'の代わりに' quit(false) 'をしなければなりません。また、このコードはWindowsでは動作しません。 'SetConsoleCtrlHandler()'を使わなければなりません。 – Timmmm

8

これらのシグナルを自分で処理しない場合は、いいえ、デストラクタは呼び出されません。ただし、オペレーティングシステムは、プログラムの終了時に使用したリソースを再利用します。

信号を自分で処理する場合は、sigaction標準ライブラリ関数をチェックアウトすることを検討してください。

+3

OSが所有するリソースを再利用します。アプリケーション内には他のリソースがあり、通常はそれらを正しく閉じるようにラップされます(そうしないと、正しく終了していないファイルなど)。 –

6

はのは、それを試してみましょう:

#include <stdio.h> 
#include <unistd.h> 

class Foo { 
public: 
    Foo() {}; 
    ~Foo() { printf("Yay!\n"); } 
} bar; 

int main(int argc, char **argv) { 
    sleep(5); 
} 

そして:

$ g++ -o test ./test.cc 
$ ./test 
^C 
$ ./test 
Yay! 

だから私はあなたがそれをキャッチする必要があります、恐れていませんよ。

SIGSTOPはキャッチできず、SIGCONTが送信されるまでプロセスを一時停止します。

関連する問題