標準シグナルとリアルタイムシグナルについての検証2:リアルタイムシグナルの動作
(プログラムの概要)
標準シグナルとリアルタイムシグナルの比較第二回です。。今回はリアルタイムシグナルの動作について検証します。プログラムの動きとしては前回の標準シグナル偏と同じく1秒おきにシグナルハンドラーが起動された回数を表示させたいと思います。
(注)今回も実験の為にシグナルハンドラー内で無駄な処理を行い重たくしてあります。

/* * sample program * signal handler (realtime signal) */ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <string.h> #include <time.h> #include <unistd.h> #include <errno.h> int sigcnt; void SignalHandler(int, siginfo_t*, void*); int _nanosleep(int, int); int main(void) { struct sigaction action; struct sigevent evp; printf("sample program(%s) start\n", __FILE__); memset(&action, 0, sizeof(action)); memset(&evp, 0, sizeof(evp)); /* set signal handler */ action.sa_sigaction = SignalHandler; action.sa_flags = SA_SIGINFO | SA_RESTART; sigemptyset(&action.sa_mask); evp.sigev_notify = SIGEV_SIGNAL; evp.sigev_signo = SIGRTMIN + 1; if(sigaction(SIGRTMIN + 1, &action, NULL) < 0){ perror("sigaction error"); exit(1); } /* loop */ while(1){ _nanosleep(1, 0); /* sleep 1 sec */ printf("%d\n", sigcnt); } return 0; } void SignalHandler(int signum, siginfo_t *info, void *ctxt) { char mem1[1024]; int i = 0; sigcnt++; for(i = 0; i < 10000; i++){ memset(mem1, 0, sizeof(mem1)); } return; } int _nanosleep(int sec, int nsec) { struct timespec req, rem; req.tv_sec = sec; req.tv_nsec = nsec; rem.tv_sec = 0; rem.tv_nsec = 0; while(nanosleep(&req, &rem)){ if(errno == EINTR){ req.tv_sec = rem.tv_sec; req.tv_nsec = rem.tv_nsec; }else{ perror("nanosleep error"); return -1; } } return 0; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
(プログラムの概要)
リアルタイムシグナルのシグナルハンドラー登録を行い、SIGRTMIN+1が通知されるとSignalHandler()が起動されるように設定します。
シグナルハンドラーが起動される度にグローバル変数sigcntをカウントアップし、main関数内で1秒に1回起動回数を表示しています。
シグナルハンドラーではカウントアップ後に無駄な処理を行い処理に時間がかかるようにしてあります。
#! /bin/bash #input : PID cnt=0 while [ $cnt -lt 10000 ]; do kill -35 $1 cnt=`expr $cnt + 1` done
1 2 3 4 5 6 7 8 9
引数として渡されるPIDのプロセスに対してSIGRTMIN+1を1万回送信します。
(注)実行した環境でのSIGRTMIN+1はSIG35です、環境によってシグナル番号が変わる可能性があります。

(動作)
gcc -Wall sigrt.c
コンパイルしたプログラムを起動させます。ps -aコマンドでプロセスIDを取得し、スクリプトを実行してみてください。
どうでしょう?今度はシグナルハンドラーが1万回起動されたと思います。リアルタイムシグナルを使ったことでシグナルが2つ以上キューイングできるようになり欠けることが無くなりました。(リアルタイムシグナルのキューイングできる最大数についてはulimit -iコマンドで調べることができます。)
(1秒に1回表示がでない)
最終的なシグナルハンドラーの起動回数は合っていますが、1秒に1回表示という部分がうまく動いていません。これは割り込み処理であるシグナルハンドラー内で無駄に重い処理が動いている為にこのような動きになってしまいます。これを解決するにはシグナルハンドラーを特定のスレッドのみで起動することで解決できます。
次回シグナルとスレッドではシグナルハンドラーを実行するスレッドを固定することで1秒に1回表示が行えるようにします。。