ユーザー定義のデストラクタを持つクラスがあります。クラスが最初にインスタンス化され、プログラムの実行中にSIGINTが発行された場合(unixでCTRL + Cを使用)、デストラクタが呼び出されますか? SIGSTP(UNIXではCTRL + Z)の動作は何ですか?
いいえ、デフォルトでは、ほとんどの信号により、プログラムが即座に異常終了します。
ただし、ほとんどの信号のデフォルトの動作は簡単に変更できます。
このコードは、通常のすべてのデストラクタの呼び出しを含め、信号をプログラムから正常に終了させる方法を示しています。
#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;
}
このプログラムを実行してcontrol-Cを押すと、「デストラクタ」という単語が印刷されているはずです。シグナルハンドラー関数(got_signal)は、何をしているのかを本当に理解していない限り、フラグを設定して静かに戻る以外の作業を行うことはめったにないことに注意してください。
ほとんどのシグナルは上記のようにキャッチ可能ですが、SIGKILLではなく、SIGKILLは暴走プロセスを強制終了するための最後の方法であり、ユーザーがプロセスをコールドでフリーズできるSIGSTOPではないため、制御できません。必要に応じてSIGTSTP(control-Z)をキャッチできますが、シグナルに関心があるのがデストラクタの動作だけである場合は、キャッチする必要はありません。最終的にはcontrol-Zの後でプロセスが起動され、実行が継続され、すべてのデストラクタが有効な状態で正常に終了します。
これらのシグナルを自分で処理しない場合、いいえ、デストラクタは呼び出されません。ただし、オペレーティングシステムは、プログラムの終了時にプログラムが使用したすべてのリソースを再利用します。
シグナルを自分で処理したい場合は、sigaction
標準ライブラリ関数を確認することを検討してください。
試してみよう:
#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
が送信されるまでプロセスを一時停止します。