準拠している標準によって異なりますが、標準Cでは、タイプの変数を変更したり、シグナルハンドラーから(または)をvolatile sig_atomic_t
呼び出したりする以上のことはできません。POSIXははるかに寛大です。シグナルハンドラーのコードは、ユーザーインタラクションでいっぱいで、POSIXでさえ許可されている限界を超えています。通常、シグナルハンドラー関数は小さくて洗練されたものにする必要があります。_Exit
abort()
signal()
シグナルハンドラ関数は次のようになっていることに注意してください。
void trata_sinal_int(int signum)
{
これにより、型の不一致に関するキャストやコンパイラの警告なしでコンパイルできます。このsignal()
関数は、呼び出されたときにシグナルハンドラをデフォルトの動作にリセットする場合があります。古典的には、シグナルハンドラー内でシグナルハンドラーを復元する必要があります。
signal(signum, trata_sinal_int);
これまでのところ、それはすべてかなり一般的で半些細なことです。
を入力するControl-Cと、システムは信号が最初に受信されたときとほぼ同じ場所に戻ります。ただし、次に何が起こるかは、それがどこにあったかによって異なります(ハンドラー内で非常に注意する必要がある理由の1つ)。たとえば、内部のフリーリストポインタを操作している最中でmalloc()
あれば、そこに戻りますがmalloc()
、ハンドラー内で再度呼び出すと、すべての地獄が解き放たれる可能性があります。システムコールの中にいる場合は、通話が中断されるか(エラー表示とで戻るerrno == EINTR
)、または中断したところから再開される場合があります。それ以外の場合は、計算が実行されていた場所に戻る必要があります。
これが、テストリグに組み込まれたコード(の修正バージョン)です。関数はpause()
、信号を待ってから戻ります。
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
static void trata_sinal_int(int signum)
{
char op[2];
signal(signum, trata_sinal_int);
printf("\nTerminate? (y/n)\n");
scanf("%s", op);
if (op[0] == 'y')
{
printf("Bye Bye\n");
exit(0);
}
}
int main(void)
{
signal(SIGINT, trata_sinal_int);
for (int i = 0; i < 3; i++)
{
printf("Pausing\n");
pause();
printf("Continuing\n");
}
printf("Exiting\n");
return(0);
}
scanf()
私は本当に安全ではないことを指摘する必要があります。サイズ2のバッファは、バッファオーバーフローへのオープンな招待です。また、システムコールのエラーチェックも行っていません。
BSD派生のMacOSX10.7.5でテストしました。signal()
BSDはずっと前に「信頼できる信号」を導入したため(POSIX以前)、このプラットフォームではのリセットが不要になる可能性があります。
ISO / IEC 9899:2011§7.14.1.1signal
機能
abort
¶5または関数を呼び出した結果以外の結果としてシグナルが発生したraise
場合、シグナルハンドラーが、値を割り当てる以外にロックフリーのアトミックオブジェクトではない静的またはスレッドの保存期間を持つオブジェクトを参照すると、動作は定義されません。として宣言されたオブジェクトに対して、またはシグナルハンドラーが、関数、関数、
関数、または関数の呼び出しを引き起こしたシグナルに対応するシグナル番号に等しい最初の引数を持つ関数volatile sig_atomic_t
以外の標準ライブラリ内の関数を呼び出すハンドラ。さらに、そのような関数の呼び出しが戻り値になる場合、errnoの値は不確定です。252)abort
_Exit
quick_exit
signal
signal
SIG_ERR
252)非同期シグナルハンドラーによってシグナルが生成された場合、動作は定義されていません。
への参照quick_exit()
はC2011で新しく追加されました。それらはC1999には存在しませんでした。
POSIX 2008
シグナルの概念に関するセクションでは、POSIXのシグナルハンドラー内で許可されていることと許可されていないことについて、かなり詳細に説明しています。