タイムイベント

 

1. 定義

タイムイベント: プログラマが望む時刻に起動されるイベントのこと

 

2. タイムイベントの使用例

送信側: エンコードタイミング、RTCP パケット送信タイミング

受信側: デコードタイミング、RTCP パケット送信タイミング

 

3. タイムイベントに関連するライブラリ関数

それぞれの関数の詳細は、Windows の場合は MSDN、Linux の場合は man コマンドによるオンラインマニュアルを参照のこと (例: man 3 usleep)。

Windows版:

マルチスレッド関数
Sleep  ミリ秒単位にスレッドの実行を中断
マルチメディアタイマ
timeGetTime ミリ秒単位にシステム時刻を取得
timeSetEvent 特定の時刻に特定の関数を起動
timeKillEvent timeSetEvent で設定されたタイマイベントの解除

Linux版:  

マルチスレッド関数
sleep  秒単位にスレッドの実行を中断
usleep  マイクロ秒単位にスレッドの実行を中断
nanosleep  ナノ秒単位にスレッドの実行を中断
gettimeofday マイクロ秒単位にシステム時刻を取得
各種GUIライブラリ毎のタイムイベント関数
準備中  

 

4. 簡単なタイムイベントプログラム

Windows版: マルチメディアタイマの利用

以下のプログラムは、1秒 (PERIOD = 1000ミリ秒) 毎にタイムイベントとしてコールバック関数 (callback) を呼び出し、そのたびに現在時刻と前回タイムイベントとの時間差を表示させるプログラムである。

他の作業を何もしていない場合は、1秒おきに正確にタイムイベントが発生する。しかし、他のアプリケーションを起動するなど、何らかの負荷をかけるとイベント発生間隔が揺らぐことがわかる。

一方 Sleep 関数は、CPU資源を無駄使いせずに処理を中断するのに有効な関数である。試しにシステムモニタ等を起動し、下のプログラムで Sleep をコメントアウトして実行してみると、CPU負荷が上がることがわかる。ただし、時間の精度は安定していない。

#include <stdio.h>
#include <windows.h>

#define PERIOD 1000 // タイムイベント間隔
#define LOOP 10

// 各種パラメータ
unsigned int curr_time, prev_time, diff_time;
unsigned int event_count = 0;

// タイムイベントとして呼び出されるコールバック関数
static void CALLBACK 
callback(unsigned int timerID, unsigned int msg, unsigned int usrParam, unsigned int dw1, unsigned int dw2) {
   // 現在時刻と前回イベントとの時間差を表示
   curr_time = timeGetTime();
   diff_time = curr_time - prev_time;
   prev_time = curr_time;
   printf("現在時刻:%d ミリ秒、前回イベントとの時間差:%d ミリ秒\n", curr_time, diff_time);
   event_count++;
}

void
main() {
   unsigned int timer;

   // タイムイベントの開始
   timer = timeSetEvent(PERIOD, 1, (LPTIMECALLBACK) callback, (DWORD) NULL, TIME_PERIODIC);
   if(timer == 0) { printf("タイムイベントの生成に失敗\n"); exit(0); }

   // ループ
   while(1) {
      Sleep(1000); // 1秒間休み。この Sleep がないと CPU 資源の無駄使い 
      if(event_count == LOOP) break;
   }

   // タイムイベントの終了
   timeKillEvent(timer);
}

 

Linux版: gettimeofday の利用

各種GUIライブラリで用意されたタイムイベント関数を使う手もあるが、ここでは gettimeofday 関数を使用し、1秒ごとに時刻を取得し、イベント間の時間差を表示するプログラムを以下に示す。

#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <time.h>

#define SECOND 1000000.0
#define LOOP 10

struct timeval current, prev;

void
function() {
   double t0, t1;

   // 時刻の取得とイベント間時間差の表示
   gettimeofday(&current, NULL); 
   t0 = current.tv_sec * SECOND + current.tv_usec;
   t1 = prev.tv_sec * SECOND + prev.tv_usec;
   prev.tv_sec = current.tv_sec;
   prev.tv_usec = current.tv_usec;
   printf("difference: %g\n", (t0-t1) / 1000.0);
}

main() {
   int i;

   // 1秒間隔で関数 function() を呼び出し
   gettimeofday(&prev, NULL);
   for(i=0; i<LOOP; i++) {
      usleep(1000000);
      function();
   }
}