signal関数は、シグナル(非同期イベント)が発生したときに、そのシグナルを受信して、シグナル特有の処理を行うシグナル処理関数(シグナルハンドラ)を登録します。
#include <signal.h>
void (*signal(int signum, void (*sighandler)(int signum)))(int signum);
signumはシグナル処理関数に対応付けする、シグナルを指定します。
*sighandlerはSIG_IGN、SIG_DFL、シグナル処理関数のアドレスのいずれかを指定します。
戻り値として、signumに対応するシグナル処理関数の値を返します。また、エラーの場合はSIG_ERRを返します。
第1引数のsignumに指定できる値は、signal.hファイルに定義されています。また、UNIX系OSの場合は、kill -lコマンドで表示できます。下表は一般的なシグナルのみで、システムにより異なります。
| 定数名 | 値 | 意味 |
|---|---|---|
| SIGINT | 2 | キーボードからの割り込み(Interrupt) |
| SIGQUIT | 3 | キーボードによる中止(Quit) |
| SIGILL | 4 | 不正な命令 |
| SIGABRT | 6 | abort関数からの中断(Abort) |
| SIGFPE | 8 | 浮動小数点例外 |
| SIGUSR1 | 10 | ユーザ定義シグナル1 |
| SIGSEGV | 11 | 不正なメモリ参照 |
| SIGUSR2 | 12 | ユーザ定義シグナル2 |
| SIGPIPE | 13 | パイプ破壊(読み手の無いパイプへの出力) |
| SIGALRM | 14 | alarmシステムコールからのタイマーシグナル |
| SIGTERM | 15 | 終了(termination) |
| SIGCHLD | 17 | 子プロセスの一旦停止(stop)または終了 |
| SIGCONT | 18 | 一旦停止(stop)からの再開 |
| SIGTSTP | 20 | 端末(tty)から入力された一旦停止(stop) |
| SIGTTIN | 21 | バックグランドプロセスのtty入力 |
| SIGTTOU | 22 | バックグランドプロセスのtty出力 |
第2引数の*sighandlerにSIG_IGNを指定した場合は、signumに指定したシグナルを無視し、SIG_DFLを指定した場合は、デフォルトの動作を行います。また、シグナル処理関数のアドレスを指定した場合は、signumを引数としてシグナル処理関数を呼び出します。
シグナル処理関数を実行すると、登録はリセットされますので、同じ処理を行いたい場合はsignal関数を再度実行する必要があります。また、SIGKILLとSIGSTOPシグナルは捕捉できませんし、無視することもできません。
次の例題プログラムはSIGINTシグナル(CtrlキーとCキーを同時に押下することにより発生)を3回発行すると終了します。
プログラム 例
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
/* ユーザ定義関数の宣言 */
void SetSignal(int SignalName);
void SigHandler(int SignalName);
void Input(void);
int main(void)
{
SetSignal(SIGINT);
Input();
return 0;
}
void Input(void)
{
while(1) {
printf('実行中!!\n');
sleep(3);
}
return;
}
/* シグナルの設定 */
void SetSignal(int p_signame)
{
if (signal(p_signame, SigHandler) == SIG_ERR) {
/* シグナル設定エラー */
printf('シグナルの設定が出来ませんでした。終了します\n');
exit(1);
}
return;
}
/* シグナル受信/処理 */
void SigHandler(int p_signame)
{
static int sig_cnt = 0;
++sig_cnt;
if (sig_cnt <= 2) {
printf('%d回目の割り込みです。無視します\n', sig_cnt);
}
else {
printf('%d回目の割り込みです。終了します\n', sig_cnt);
exit(0);
}
/* シグナルの再設定 */
SetSignal(p_signame);
return;
}
例の実行結果
$ ./signal.exe 実行中!! 実行中!! 実行中!! 1回目の割り込みです。無視します 実行中!! 実行中!! 2回目の割り込みです。無視します 実行中!! 実行中!! 実行中!! 実行中!! 3回目の割り込みです。終了します $