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回目の割り込みです。終了します
$