EventWaitHandle
更新 : 2007 年 11 月
EventWaitHandle クラスを使用すると、スレッドは通知および通知の待機により、互いに通信できます。イベント待機ハンドル (単にイベントとも呼ばれます) は、通知を受けて、1 つ以上の待機中のイベントを解放できる待機ハンドルです。通知を受けると、イベント待機ハンドルは手動または自動でリセットされます。EventWaitHandle クラスは、ローカルのイベント待機ハンドル (ローカル イベント) または名前付きのシステム イベント待機ハンドル (名前付きのイベントまたはシステム イベント。すべてのプロセスから参照できます) を表すことができます。
メモ : |
---|
イベント待機ハンドルは、通常 .NET Framework でイベントと呼ばれるものとは異なります。デリゲートやイベント ハンドラは関連していません。"イベント" という言葉で説明されているのは、それらがこれまでオペレーティング システム イベントと呼ばれており、待機ハンドルの通知はイベントが発生した待機中のスレッドを示すためです。 |
ローカル イベント待機ハンドルと名前付きイベント待機ハンドルはどちらも、システム同期オブジェクトを使用します。これは SafeWaitHandle ラッパーによって保護されており、リソースが確実に解放されるようにします。IDisposable.Dispose メソッドを使用すると、オブジェクトを使い終わったらすぐにリソースを解放できます。
自動的にリセットされるイベント待機ハンドル
自動リセット イベントを作成するには、EventWaitHandle オブジェクトを作成するときに EventResetMode.AutoReset を指定します。その名前が示すとおり、この同期イベントは通知を受けたときに、単一の待機中のスレッドを解放した後、に自動的にリセットされます。イベントを通知するには、その Set メソッドを呼び出します。
通常、自動リセット イベントは、単一のスレッドのリソースに一度に排他アクセスを提供するために使用されます。スレッドは、WaitOne メソッドを呼び出してリソースを要求します。他のスレッドに待機ハンドルがない場合、メソッドは true を返し、呼び出し元スレッドはリソースの制御権を持ちます。
重要 : |
---|
あらゆる同期機構と同様に、すべてのコード パスが適切な待機ハンドルを待ってから、保護されているリソースにアクセスする必要があります。スレッドの同期は連携しています。 |
自動リセット イベントが通知を受けたとき、大気中のスレッドがない場合は、スレッドが待機中になるまでシグナル状態のままです。イベントはスレッドを解放してすぐにリセットされ、以降のスレッドをブロックします。
手動でリセットされるイベント待機ハンドル
手動リセット イベントを作成するには、EventWaitHandle オブジェクトを作成するときに EventResetMode.ManualReset を指定します。その名前が示すとおり、この同期イベントは、通知を受けた後に手動でリセットする必要があります。Reset メソッドを呼び出してリセットするまで、イベント ハンドルを待っているスレッドはすぐに続行され、ブロックされません。
手動リセット イベントは、家畜を囲うゲートのように動作します。イベントが通知を受けないと、待機中のスレッドは柵の中の馬のようにブロックされます。イベントが通知を受けると、その Set メソッドを呼び出して、すべての待機中のスレッドは続行できます。イベントは、その Reset メソッドが呼び出されるまで、シグナル状態のままです。これにより、手動リセット イベントは、1 つのスレッドがタスクを終えるまで待機させる必要のあるスレッドを保持する理想的な方法となっています。
馬が柵を出るのと同様に、解放されたスレッドがオペレーティング システムによってスケジュールされ、実行が再開されるには時間がかかります。すべてのスレッドの実行が再開される前に Reset メソッドが呼び出された場合、残りのスレッドは再びブロックされます。再開されるスレッドとブロックされるスレッドは、システムのロード、スケジューラを待っているスレッドの数など、ランダムな要素によって異なります。イベントを通知したスレッドが通知後に終了した場合 (これは最も一般的な使用パターンです)、これは問題ではありません。すべての待機中のスレッドが再開された後で、イベントを通知したスレッドに新しいタスクを開始させる場合は、すべての待機中のスレッドが再開されるまで、そのスレッドをブロックする必要があります。それ以外の場合は競合状態で、コードの動作は予測できません。
自動イベントと手動イベントの共通の機能
通常、ブロックされていないスレッドが Set メソッドを呼び出して、いずれかの待機中のスレッド (自動リセット イベントの場合) またはそれらすべて (手動リセット イベントの場合) を解放するまで、1 つ以上のスレッドが EventWaitHandle でブロックします。スレッドは、静的な WaitHandle.SignalAndWait メソッドを呼び出すことにより、EventWaitHandle の通知とブロックを分割できない操作として行うことができます。
EventWaitHandle オブジェクトは、静的な WaitHandle.WaitAll および WaitHandle.WaitAny メソッドと共に使用できます。EventWaitHandle および Mutex クラスはいずれも WaitHandle から派生するため、両方のクラスをこれらのメソッドで使用できます。
名前付きのイベント
Windows オペレーティング システムでは、イベント待機ハンドルに名前を付けることができます。名前付きのイベントはシステム全体で使用されます。つまり、いったん名前付きのイベントを作成すると、すべてのプロセスのすべてのスレッドがそれを参照できます。したがって、名前付きのイベントを使用して、スレッドだけでなくプロセスのアクティビティも同期できます。
名前付きのシステム イベントを表す EventWaitHandle オブジェクトを作成するには、イベントの名前を指定するいずれかのコンストラクタを使用します。
メモ : |
---|
名前付きのイベントはシステム全体で使用されるため、複数の EventWaitHandle オブジェクトで同じ名前付きイベントを表すことができます。コンストラクタまたは OpenExisting メソッドを呼び出すたびに、新しい EventWaitHandle オブジェクトが作成されます。同じ名前を繰り返し指定すると、同じ名前付きイベントを表す複数のオブジェクトを作成できます。 |
名前付きのイベントを使用する際には注意が必要です。それらはシステム全体で使用されるので、別のプロセスが同じ名前を使用すると、スレッドが予期せずにブロックされる場合があります。悪意のあるコードが同じコンピュータで実行されると、サービス拒否攻撃の基本としてこれが使用される場合があります。
アクセス制御セキュリティを使用して、名前付きのイベントを表す EventWaitHandle オブジェクトを保護します。可能であれば EventWaitHandleSecurity オブジェクトを指定するコンストラクタを使用します。また、SetAccessControl メソッドを使用してアクセス制御セキュリティを適用できます。ただし、こうすると、イベント待機ハンドルが作成されてから保護されるまでの間に、脆弱性が生じます。アクセス制御セキュリティでイベントを保護すると、悪意のある攻撃を防ぐのに役立ちますが、予期しない名前の衝突の問題解決にはなりません。
メモ : |
---|
EventWaitHandle クラスとは異なり、派生したクラスである AutoResetEvent および ManualResetEvent は、ローカルの待機ハンドルのみを表すことができます。名前付きのシステム イベントを表すことはできません。 |