setitimerが廃止予定関数ということだったので、timer_settime関数を使用した定周期処理も作ってみた。
前のソースを改造して作成。
#include <stdio.h> #include <string.h> #include <unistd.h> #include <time.h> #include <sys/time.h> #include <signal.h> #include <pthread.h> #include <errno.h> int main() { // setitimerにより通知されるシグナルをマスク sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGALRM); pthread_sigmask(SIG_BLOCK, &sigset, NULL); // タイマ設定 5秒毎に通知 timer_t timerid; const struct timespec interval = { 5, 0 }; const struct itimerspec itimer = {interval, interval}; int ret = timer_create(CLOCK_REALTIME, NULL, &timerid); if( ret == -1) { perror("timer_create"); return -1; } ret = timer_settime(timerid, TIMER_ABSTIME, &itimer, NULL); if ( ret != 0 ) { perror("timer_settime"); return -1; } int i; for ( i=0; i<10; i++ ) { int signo; sigwait(&sigset, &signo); struct timeval tv; gettimeofday(&tv, NULL); char timebuf[26]; ctime_r(&tv.tv_sec, timebuf); *strchr(timebuf, '\n') = '\0'; printf("[%s] [%06d] signal[%d] recieved.\n", timebuf, tv.tv_usec, signo); // たまに時間かかる処理がある想定 if ( i % 4 == 3 ) { unsigned int waittime = 7; printf("wait %d seconds.\n", waittime); sleep(waittime); } } ret = timer_delete(timerid); if ( ret != 0 ) { perror("timer_delete"); return -1; } return 0; }
実行。
[~]$ cc timer2.c -lpthread -lrt [~]$ ./a.out [Wed Apr 3 18:12:29 2013] [380927] signal[14] recieved. [Wed Apr 3 18:12:30 2013] [000964] signal[14] recieved. [Wed Apr 3 18:12:35 2013] [001200] signal[14] recieved. [Wed Apr 3 18:12:40 2013] [001446] signal[14] recieved. wait 7 seconds. [Wed Apr 3 18:12:47 2013] [001920] signal[14] recieved. [Wed Apr 3 18:12:50 2013] [000928] signal[14] recieved. [Wed Apr 3 18:12:55 2013] [001189] signal[14] recieved. [Wed Apr 3 18:13:00 2013] [001413] signal[14] recieved. wait 7 seconds. [Wed Apr 3 18:13:07 2013] [001828] signal[14] recieved. [Wed Apr 3 18:13:10 2013] [000898] signal[14] recieved. [~]$
シグナル通知による定周期処理なので、シグナル受信側がシグナル受信可能にならないと処理は動かない。
シグナル送信は、シグナル受信側が受信してるかどうかに関わらず行われる模様。
(追記)
よく考えたら、この方式、以下の問題がある。
- SIGALRMはプロセスに配信されるので、プロセス全体としてSIGALRMのブロックが必要。
- SIGALRMを受信するスレッドは1スレッドに限定する必要がある。(複数スレッドで同一シグナルのwaitを行うと、どのスレッドに配信されるか分からない)
- SIGALRMを受信する側で何のイベントに対する通知かを知る術がない。よって、1プロセスの中で複数のタイマ設定を行うことは出来ない。
3つ目は致命的なので、この方式は使い物にならなそうだな。。
追加で調べてみたら、timerfd_settimeというAPIがあって、これなら1プロセスの複数イベント設定も可能そう。
と思ったら、新しいkernelから導入されたAPIらしく、CentOS5.9には入ってなかった。。