Windowsコード集 上のページ

#0003 タイマー動作あれこれ

Windowsでは周期呼び出しには、いろいろな方法があります。 簡単な物から順番に説明していきます。

WM_TIMERメッセージ
最もスタンダードな方法です。各種RADツールでは、Timer1_Timer()とかいった感じの名前で呼ばれるメソッドの正体でもあります。 しかしながら、このタイマーはWM_TIMERメッセージ終了後から何ミリ秒待つかという方法で呼び出されるので、正確な時間計測はできません。

-----------> "WM_TIMER" ---------->"WM_TIMER" ---------->
(待ち)(呼び出し)(待ち)(呼び出し)(待ち)

つまりWM_TIMERメッセージでの処理内容が長ければ長いほど、計測誤差はどんどん悪くなっていきます。

宣言: SetTimer
開放: KillTimer
呼び出し: WindowProcコールバック関数内の、WM_TIMERメッセージ

timeSetEventコールバック
1ミリ秒単位(詳しくは、10ミリ秒単位らしいですが)で非常に正確な時間計測を行う事ができます。
しかし、コールバックの処理が呼び出し間隔よりも短い時間で処理されなければならず、もしコールバックが長引いてしまった場合に動作が不安定になります。

----------------> ---------------->---------------->
(待ち)(待ち)(待ち)
|→(呼び出し)|→(呼び出し)|→(呼び出し)

宣言: timeSetEvent
開放: timeKillEvent
呼び出し: timeSetEventコールバック関数

timeGetTime,GetTickCount関数
上の2つは、基本的にOS自身がもつ割り込み(厳密には違うけど)を利用したものです。 timeGetTime(GetTickCount)はOSが持つ内部タイマーを利用して、timeSetEventとは別の方法で周期呼び出しを実現します。
利用できる関数ですが、マルチメディア関数として用意されたtimeGetTimeと、OS自身が持っているGetTickCountの2つがあります。 どちらも動作は同じですが、timeGetTimeの方がやや正確に時間計測ができるようです。

呼び出し方法は、通知メッセージのアイドリング時に行うと便利です。
以下はサンプルコードです。
#define TIMEOUT      100  // 100msで周期呼び出しする
DWORD tim;                // 次の待ち時間
DWORD wtim;
MSG msg;

tim = timeGetTime() + TIMEOUT;
while(1){
    if(PeekMessage(&msg,NULL,0,0)){
        if(msg.message == WM_QUIT)break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    if(!IsWindow(hwnd))break;

    wtim = timeGetTime();
    if(tim <= wtim){
        tim = wtim + TIMEOUT;

        // 周期呼び出し
           :
           :
    }
}



上のページ