Version 14.12
イベントを使おう!
「同期オブジェクト4つめはイベントです」
イベント ( Event )
『イベントって、催し物のイベントと同じ?』
「意味としては同じだけど、そこにはあまりこだわらない方がいいかも。同
期オブジェクトとしての【イベント】は、たぶん同期オブジェクトの中で一
番わかりやすくてシンプルです」
『今までのもそんなに複雑じゃなかったけど』
「でも〈バトン〉って概念は今までなかったでしょ。イベントは、簡単に言
うと〈ただのスイッチ〉」
『うわ簡単そう』
「でも、関数の数は一番多いです」
HANDLE g_hEvent = NULL;
const char *const EVENT_NAME= "ProcessesEvent";
// イベントを作成します。
void Create()
{
g_hEvent = CreateEvent( NULL, TRUE, FALSE, EVENT_NAME );
TRACE( "%x\n", g_hEvent );
}
// イベントを取得します。
void Open()
{
g_hEvent = OpenEvent( EVENT_ALL_ACCESS, FALSE, EVENT_NAME );
TRACE( "%x\n", g_hEvent );
}
// イベントをセットします。
void Set()
{
BOOL b = SetEvent( g_hEvent );
TRACE( "%d\n", b );
}
// イベントを監視して待機状態に入ります。
void Wait()
{
TRACE( "待機開始。\n" );
DWORD dwResult = WaitForSingleObject( g_hEvent, 50000 );
if( dwResult == WAIT_TIMEOUT )
{
TRACE( "タイムアウト。\n" );
}
else
{
TRACE( "待機終了。\n" );
}
}
// イベントをリセットします。
void Reset()
{
BOOL b = ResetEvent( g_hEvent );
TRACE( "%d\n", b );
}
// イベントを一瞬だけオンにします。
void Pulse()
{
BOOL b = PulseEvent( g_hEvent );
TRACE( "%d\n", b );
}
// イベントを削除します。
void Close()
{
CloseHandle( g_hEvent );
}
『うわ、7つもある!』
「関数だけ抜き出すとこんな感じ」
void Create()
void Open()
void Set()
void Wait()
void Reset()
void Pulse()
void Close()
『 Release() や Cancel() の代わりに…… Reset() かな?』
「そうだね。 Set() Reset() Pulse() がイベント独自のもの。この3つで
イベントを操作します」
『 Pulse() って想像つかない……』
「では、ひとつずつ関数を見ていきます。まずはハンドルと名前」
HANDLE g_hEvent = NULL;
const char *const EVENT_NAME= "ProcessesEvent";
『他のと同じ、名前で区別するのね』
「この辺はどの同期オブジェクトも一緒。次にイベントの作成」
// イベントを作成します。
void Create()
{
g_hEvent = CreateEvent( NULL, TRUE, FALSE, EVENT_NAME );
TRACE( "%x\n", g_hEvent );
}
『真ん中の TRUE と FALSE が謎』
「第2引数の TRUE は、プログラムでイベントのセットとリセットを切り替
えられるようにするためのもの。第3引数の FALSE は、最初の状態。 TRUE
だとセット、 FALSE だとリセット」
『セットとかリセットとかよくわかんない』
「言い換えると」
セット :シグナルがオンの状態
リセット:シグナルがオフの状態
『ああ!』
「ここで重要なのは、イベントは〈シグナルの状態がずっと維持される〉と
いうことです」
『どゆこと?』
「ミューテックスを思い出して」
『 Version 14.06 ( No.273 ) さんしょー』
「ミューテックスはバトン。ミューテックスはバトンを渡した瞬間に渡した
相手だけシグナルをオンにしました」
『だから他の待ってるのはシグナルがオフのまま、待ち続けてたね』
「対して、イベントはちょっと特殊。まずリセット=シグナルがオフの場合
には、各プロセスがこのイベントを監視すると待機しつづけます」
『シグナルがオフなんだからそうだよね』
「そこで、イベントをセット=シグナルをオンにすると、待機している全て
のプロセスにシグナルオンが伝わります」
『ひとつだけじゃないんだ!』
「しかも、シグナルがオンの状態が維持されるので、このあと他のプロセス
が監視しても、シグナルがオンだからすぐに待機終了します」
『はー、なんかそれって、ホントの意味での信号って感じね』
「そうだね。セットは青、リセットは赤。イベントはそういう使い方をする
同期オブジェクトなんです」
『ホントに他の同期オブジェクトよりもわかりやすい……』
「他の同期オブジェクトは〈シグナルがひとつのプロセスにしか送られな
い〉とかのわかりづらい点があるからね。さて、話を戻すと、この例では
第3引数が FALSE なので、最初の状態はリセットになっています」
『シグナルがオフってことね』
「この状態を変更するのが次のふたつの関数」
// イベントをセットします。
void Set()
{
BOOL b = SetEvent( g_hEvent );
TRACE( "%d\n", b );
}
// イベントをリセットします。
void Reset()
{
BOOL b = ResetEvent( g_hEvent );
TRACE( "%d\n", b );
}
「 SetEvent() はセット=シグナルオンに、 ResetEvent() はリセット=
シグナルオフに切り替えます」
『これで切り替えるわけね』
「あともうひとつ、特別な関数があります」
// イベントを一瞬だけオンにします。
void Pulse()
{
BOOL b = PulseEvent( g_hEvent );
TRACE( "%d\n", b );
}
「この PulseEvent() は、一瞬だけセットして、すぐリセットにする関数で
す」
『スイッチをカチャカチャって切り替える感じ?』
「そういうこと。一瞬だけシグナルがオンになるから、待機してるすべての
プロセスはすぐに待機終了になります」
『で、すぐにシグナルオフに戻るから、そのあとで監視すると待機しっぱな
しってわけね』
「そういうこと。この関数は、とりあえず待機してるものすべてリセットし
たい場合に使います」
『でも SetEvent() でもいいんじゃない?』
「 SetEvent() はずっとシグナルオンのままだからね。たとえば待機してい
る数を数えておいて、10になったらすぐリセット、その10だけ処理をさ
せて、そのあと監視しに来たらそれは待機してもらう、で、それが10にな
るまで」
『ってゆーのを繰り返すわけね。並んで10人だけ入っていい、みたいな感
じ?』
「そういうこと。イベントはそういう使い方もできるってことで」
/*
Preview Next Story!
*/
『んー』
「どうしたの?」
『他の同期オブジェクトと違うから違和感が』
「こっちの方がわかりやすいのに」
『それはそうなんだけど……』
「というわけで次回」
< Version 14.13 イベントを使ってみる! >
『につづく!』
「やっぱ染まってるんじゃない?」
『それは認めない!!』