今回は、CountdownEventクラスについて。
CountdownEventクラスは、.NET 4.0からSystem.Threading名前空間に追加されたクラスです。
CountdownEventクラスは、ManualResetEventSlimクラスなどと同じ待機を行う為のオブジェクトです。
ManualResetEventSlimクラスは、一回Setメソッドを呼ぶとシグナル状態になりますが
CountdownEventは、文字通り一定回数のカウントを持ち、それが全てデクリメントされればシグナル状態となります。
Javaやってる方は、CountDownLatchクラスと大体同じと思って頂ければオッケイです。
結構使い勝手が良いので、私はよく利用する方です。
ManualResetEventSlimクラスと同じく、CountdownEventクラスもキャンセルトークンを
受け付けることが可能です。
CancellationTokenは、.NET 4.0から追加されたキャンセル処理のための新たな仕組みです。
タスク並列ライブラリ (TPL) でよく利用されます。
キャンセルトークンを指定するWaitメソッドの場合、通常のシグナル状態になるまで待機すると同時に
キャンセルされたか否かも検知するようになります。
注意点として、キャンセルトークンを指定した場合、キャンセル操作が行われると
OperationCanceledExceptionが発生するので、try-catchが必須となります。
複数回に分けて、このクラスの使い方を取り上げていきます。
まずは、一番シンプルなタイプから。
初期カウント数を1に設定し、それを別の処理がデクリメントします。
メインスレッド側は、カウントが0になるまで待機します。
丁度、ManualResetEventSlimを利用した状態と同じです。
本来、このクラスはThreadPoolなどを利用しているマルチスレッドプログラミングの際に
利用することが多いのですが、今回は面倒なのでTaskを利用しています。
本当は、Taskを利用している場合は、Taskで待機などを行った方が楽です。w
以下、サンプルです。
#region CountDownEventSamples-01 /// <summary> /// CountdownEventクラスについてのサンプルです。(1) /// </summary> /// <remarks> /// CountdownEventクラスは、.NET 4.0から追加されたクラスです。 /// JavaのCountDownLatchクラスと同じ機能を持っています。 /// </remarks> public class CountdownEventSamples01 : IExecutable { public void Execute() { // // 初期カウントが1のCountdownEventオブジェクトを作成. // // この場合、どこかの処理にてカウントを一つ減らす必要がある。 // カウントが残っている状態でWaitをしていると、いつまでたってもWaitを // 抜けることが出来ない。 // using (CountdownEvent cde = new CountdownEvent(1)) { // 初期の状態を表示. Console.WriteLine("InitialCount={0}", cde.InitialCount); Console.WriteLine("CurrentCount={0}", cde.CurrentCount); Console.WriteLine("IsSet={0}", cde.IsSet); Task t = Task.Factory.StartNew(() => { Thread.Sleep(TimeSpan.FromSeconds(1)); // // カウントをデクリメント. // // Signalメソッドを引数なしで呼ぶと、1つカウントを減らすことが出来る。 // (指定した数分、カウントをデクリメントするオーバーロードも存在する。) // // CountdownEvent.CurrentCountが0の状態で、さらにSignalメソッドを呼び出すと // InvalidOperationException (イベントのカウントを 0 より小さい値にデクリメントしようとしました。)が // 発生する。 // cde.Signal(); cde.Signal(); // このタイミングで例外が発生する. }); try { t.Wait(); } catch (AggregateException aggEx) { foreach (Exception innerEx in aggEx.Flatten().InnerExceptions) { Console.WriteLine("ERROR={0}", innerEx.Message); } } // // カウントが0になるまで待機. // cde.Wait(); // 現在の状態を表示. Console.WriteLine("InitialCount={0}", cde.InitialCount); Console.WriteLine("CurrentCount={0}", cde.CurrentCount); Console.WriteLine("IsSet={0}", cde.IsSet); } } } #endregion
実行結果は以下のようになります。
InitialCount=1 CurrentCount=1 IsSet=False ERROR=イベントのカウントを 0 より小さい値にデクリメントしようとしました。 InitialCount=1 CurrentCount=0 IsSet=True
================================
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場