C言語入門講座。関数、サンプル集を参考にして、 C言語をマスターしよう。初心者から上級者まで。

インターバルタイマーの設定と値の取得をする

2012.08.10

setitimer関数はインターバル・タイマーの設定を行い、getitimer関数はインターバル・タイマーの値の取得を行います。

システムは1つのプロセスにつき3個のインターバル・タイマーを提供し、それぞれのタイマーは別々の時間種別で減少します。どのタイマーも満了する(0になる)とプロセスにシグナルを送り、(設定によっては)再び開始します。

この関数は、C言語のライブラリ関数(標準関数)ではありませんので、コンパイラにより、使えない場合があります。

#include <sys/time.h>
int getitimer(int which, struct itimerval *gvalue);
int setitimer(int which, const struct itimerval *svalue,
          struct itimerval *ovalue);

whichはタイマーの種類を指定します。
*gvalueはタイマーの現在の値を格納する構造体を指定します。
*svalueはタイマーに設定する値が格納されている構造体を指定します。
*ovalueはタイマーの古い値を格納する構造体を指定します。ただし、0を指定した場合は格納しません。

戻り値として、処理が成功した場合は0が、失敗した場合は-1を返します。

第1引数のwhichで指定するタイマーは、次の値で指定します。

意味
ITIMER_REAL 実時間(real time)で減少し、満了するとSIGALRMシグナルを送ります。
ITIMER_VIRTUAL プロセスが実行されている間のみ減少し、満了するとSIGVTALRMシグナルを送ります。
ITIMER_PROF プロセスが実行されていて、かつシステムがそのプロセスのために処理を行なっている間に減少し、満了するとSIGPROFシグナルを送ります。

タイマーの値を格納するitimerval構造体は、次のように定義してあります。

struct itimerval {
  struct timeval it_interval; /* next value */
  struct timeval it_value;    /* current value */
};

struct timeval {
  long tv_sec;                /* seconds */
  long tv_usec;               /* microseconds */
};

getitimer関数の場合は、it_valueメンバーにタイマーの残り時間が設定され、it_intervalメンバーに初期値が設定されます。なお、タイマーがオフの場合は、it_valueメンバーはゼロが設定されます。

it_valueメンバーの値は0へ向けて減っていき、0になる(タイマーが満了する)とシグナルを生成し、it_intervalメンバーの値で初期化されます。タイマーが0に設定された場合(it_valueメンバーの値が0か、タイマーが満了した時にit_intervalメンバーの値が0の場合)は停止します。なお、タイマーの値はtv_secメンバー(秒)とtv_usecメンバー(マイクロ秒)の値を合算したものになります。

次の例題プログラムは、子プロセスがCPUを500ミリ秒使う毎に、’*’記号を1個表示します。

プログラム 例

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <limits.h>
#include <sys/time.h>
#include <signal.h>
#define MILLI_SEC 1000

/* ユーザ定義関数の宣言 */
void SetSignal(int SignalName);
void SigHandler(int SignalName);

int main()
{
  int              use_cpu;
  struct itimerval value =
         {0, 500 * MILLI_SEC, 0, 500 * MILLI_SEC};
  struct itimerval ovalue = {0, 0, 0, 0};;

  /* シグナルの設定 */
  SetSignal(SIGVTALRM);

  if (fork() == 0) {
    /* 子プロセス */
    printf('子プロセス開始\n');

    /* インターバルタイマーの設定 */
    if (setitimer(ITIMER_VIRTUAL, &value, &ovalue) == 0) {
      /* CPUを使う */
      for (use_cpu = 0; use_cpu < INT_MAX; ++use_cpu)
        ;
    }

    printf('\n子プロセス終了\n');
  }
  else {
    /* 親プロセス */
    wait(NULL);
    printf('親プロセス終了\n');
  }

  return 0;
}

/* シグナル受信/処理 */
void SigHandler(int p_signame)
{
  printf('*');
  fflush(stdout);

  /* シグナルの再設定 */
  SetSignal(p_signame);

  return;
}

/* シグナルの設定 */
void SetSignal(int p_signame)
{
  if (signal(p_signame, SigHandler) == SIG_ERR) {
    /* シグナル設定エラー  */
    perror('SetSignal() ');
  }

  return;
}

例の実行結果

$ ./itimer.exe
子プロセス開始
**********
子プロセス終了
親プロセス終了
$

関連記事