Version 14.10
タイマーを使おう!
「同期オブジェクト3つめはタイマーです」
タイマー ( Waitable timer )
「タイマーも仕組みそのものは難しくありません」
『バトンとかそんな感じ?』
「そういうこと。同じように走ることを例に取ると」
・一定時間毎に走り出す
「のがタイマーかな」
『?』
「選手A、B、Cがいる時に、まずAが走って、その1分後にBが走って、
そのさらに1分後にCが走る」
『ハンデみたいな感じ?』
「そんな感じ。まずはいつも通り、プログラムを見てもらおうか」
namespace B1
{
HANDLE g_hTimer = NULL;
const char *const TIMER_NAME= "ProcessesTimer";
// タイマーを作成します。
void Create()
{
g_hTimer = CreateWaitableTimer( NULL, FALSE, TIMER_NAME );
TRACE( "%x\n", g_hTimer );
}
// タイマーを取得します。
void Open()
{
g_hTimer = OpenWaitableTimer( TIMER_ALL_ACCESS, FALSE, TIMER_NAME );
TRACE( "%x\n", g_hTimer );
}
// タイマーをセットします。
void Set()
{
// タイマーを開始するまでの100ナノ秒数。
const int DUE_NSEC = -5 * 1000 * 1000 * 10;
LARGE_INTEGER largeInteger;
largeInteger.QuadPart = DUE_NSEC;
// タイマーの間隔のミリ秒数。
const int INTERVAL_MSEC = 15000;
BOOL b
= SetWaitableTimer
( g_hTimer
, &largeInteger
, INTERVAL_MSEC
, NULL
, NULL
, FALSE
);
TRACE( "%d\n", b );
}
// タイマーを監視して待機状態に入ります。
void Wait()
{
TRACE( "待機開始。\n" );
DWORD dwResult = WaitForSingleObject( g_hTimer, 120000 );
if( dwResult == WAIT_TIMEOUT )
{
TRACE( "タイムアウト。\n" );
}
else
{
TRACE( "待機終了。\n" );
}
}
// タイマーをキャンセルします。
void Cancel()
{
LONG lCount = 0;
BOOL b = CancelWaitableTimer( g_hTimer );
TRACE( "%d\n", b );
}
// タイマーを削除します。
void Close()
{
CloseHandle( g_hTimer );
}
}
「前回と関数の数と名前が違うから注意して」
『 Set() が追加されて…… Release() が Cancel() になってる?』
「そうです。このあたりはタイマーが他の同期オブジェクトと違う点かな。
じゃあ、ひとつずつ見ていこうか」
HANDLE g_hTimer = NULL;
const char *const TIMER_NAME= "ProcessesTimer";
『これはいつもと同じ、ハンドルと名前ね』
「この辺はどの同期オブジェクトも同じだから。次も同じ」
// タイマーを作成します。
void Create()
{
g_hTimer = CreateWaitableTimer( NULL, FALSE, TIMER_NAME );
TRACE( "%x\n", g_hTimer );
}
「これはタイマーを作る関数。引数も他と同じ」
『じゃ、次』
// タイマーを取得します。
void Open()
{
g_hTimer = OpenWaitableTimer( TIMER_ALL_ACCESS, FALSE, TIMER_NAME );
TRACE( "%x\n", g_hTimer );
}
「これも同じ、元々作ってあるタイマーを取得します」
『 TIMER_NAME と同じ名前のタイマーを取得するんだね』
「そういうこと。では次、これはちょっとややこしいです」
『追加された関数だね』
// タイマーをセットします。
void Set()
{
// タイマーを開始するまでの100ナノ秒数。
const int DUE_NSEC = -5 * 1000 * 1000 * 10;
LARGE_INTEGER largeInteger;
largeInteger.QuadPart = DUE_NSEC;
// タイマーの間隔のミリ秒数。
const int INTERVAL_MSEC = 15000;
BOOL b
= SetWaitableTimer
( g_hTimer
, &largeInteger
, INTERVAL_MSEC
, NULL
, NULL
, FALSE
);
TRACE( "%d\n", b );
}
「この関数は、タイマーを実際にセットします」
『時間セットしてオンにする、みたいな?』
「そういうこと。 OpenWaitableTimer() は作るだけだから、この
SetWaitableTimer() でセットしなきゃいけないんです」
『でも数字多くてよくわかんない……』
「使う数はふたつ。まずひとつめは、タイマーが一番最初にオンになるまで
の時間」
// タイマーを開始するまでの100ナノ秒数。
const int DUE_NSEC = -5 * 1000 * 1000 * 10;
『ナノ秒……?』
「1秒の1000分の1がミリ秒、ミリ秒の1000分の1がマイクロ秒、
マイクロ秒の1000分の1がナノ秒。あ、この単位は100ナノ秒だか
ら、マイクロ秒の10分の1が100ナノ秒」
『すごく小さな数……』
「でもナノって数はあまり気にしなくていいかも。この例では 5 だから
5秒後ってこと」
『ん? マイナス付いてるけど』
「実はこの第2引数にはふたつの使い道があるんです」
・正の数:1601/01/01 00:00:00 からののべ時間
・負の数:呼び出した瞬間からののべ秒
「つまり、正の時間を使えば〈2004年1月1日0時0分0秒から〉とい
うふうにきっちりとした時間からタイマーを開始できるんです」
『そっちはタイマーっていうよりアラームだね』
「どっちの場合でも、 LARGE_INTEGER っていう構造体に入れて渡します」
LARGE_INTEGER largeInteger;
largeInteger.QuadPart = DUE_NSEC;
「この構造体は 64 ビットサイズの整数値を入れられます」
『 64 ビットっていうと…… int が 32 ビットだからその倍だね』
「 int の最大値より、 2 の 32 乗大きい数を入れられるってことだから」
『うわすご!』
「100ナノ秒だし、正の数の時には大きな数になるからね……で、今のが
スタートするまでの時間。次はタイマーの間隔」
// タイマーの間隔のミリ秒数。
const int INTERVAL_MSEC = 15000;
「タイマーは一定時間毎にオンになるから、その間隔」
『これはミリ秒数だから……15秒間隔だよね』
「そう。この例だと15秒間隔でオンになります。このタイマーは、この関
数で止めます」
// タイマーをキャンセルします。
void Cancel()
{
LONG lCount = 0;
BOOL b = CancelWaitableTimer( g_hTimer );
TRACE( "%d\n", b );
}
『これで止めるまで止まらない?』
「そういうこと。というわけで次回は実際に使ってみます」
/*
Preview Next Story!
*/
『タイマーって、ネットで調べてもあまり例ないよね』
「ちょっと使い方が難しいっていうのもあるけど……
『けど?』
「一番の理由は、使い道がないことかな」
『使い道ないの?』
「というわけで次回」
< Version 14.11 タイマーを使ってみる! >
『につづく!』
「ないっていうか、はっきりしないって言うか……」
『おまえがはっきりしろ』