いろいろ備忘録日記

主に .NET と Python絡みのメモを公開しています。

.NET クラスライブラリ探訪-044 (System.Threading.CountdownEvent(2))(N個の処理を待機, .NET 4.0)


今回も、CountdownEventクラスについて。
CountdownEventクラスは、.NET 4.0からSystem.Threading名前空間に追加されたクラスです。


今回は、N個の処理が存在している状態で、ある規定数分が終了したら
メインスレッドの待機を解除して、先に進むサンプルです。
CountdownEventがよく利用されるパターンだと思います。


何個完了したら待機を解除するかの数を、処理数分にしたら
全処理が完了した後に待機を解除することになります。


以下、サンプルです。

    #region CountdownEventSamples-02
    /// <summary>
    /// CountdownEventクラスについてのサンプルです。(2)
    /// </summary>
    /// <remarks>
    /// CountdownEventクラスは、.NET 4.0から追加されたクラスです。
    /// JavaのCountDownLatchクラスと同じ機能を持っています。
    /// </remarks>
    public class CountdownEventSamples02 : IExecutable
    {
        public void Execute()
        {
            const int LEAST_TASK_FINISH_COUNT = 3;
            
            //
            // 複数のスレッドから一つのCountdownEventをシグナルする.
            //
            // CountdownEventがよく利用されるパターンとなる。
            // N個の処理が規定数終了するまで、メインスレッドの続行を待機するイメージ.
            //
            // 以下の処理では、5つタスクを作成して、3つ終わった時点で
            // メインスレッドは処理を続行するようにする.
            //
            // N個の処理が全部終了するまで、メインスレッドの続行を待機する場合は
            // CountdownEventのカウントをタスクの処理数と同じにすれば良い。
            //
            using (CountdownEvent cde = new CountdownEvent(LEAST_TASK_FINISH_COUNT))
            {
                // 初期の状態を表示.
                Console.WriteLine("InitialCount={0}", cde.InitialCount);
                Console.WriteLine("CurrentCount={0}", cde.CurrentCount);
                Console.WriteLine("IsSet={0}", cde.IsSet);
                
                Task[] tasks = new Task[]
                {
                    Task.Factory.StartNew(TaskProc, cde),
                    Task.Factory.StartNew(TaskProc, cde),
                    Task.Factory.StartNew(TaskProc, cde),
                    Task.Factory.StartNew(TaskProc, cde),
                    Task.Factory.StartNew(TaskProc, cde)
                };
                
                //
                // 3つ終わるまで待機.
                //
                cde.Wait();
                Console.WriteLine("5つのタスクの内、3つ終了");
                
                Console.WriteLine("メインスレッド 続行開始・・・");
                Thread.Sleep(TimeSpan.FromSeconds(1));
                
                //
                // 残りのタスクを待機.
                //
                Task.WaitAll(tasks);
                Console.WriteLine("全てのタスク終了");
                
                // 現在の状態を表示.
                Console.WriteLine("InitialCount={0}", cde.InitialCount);
                Console.WriteLine("CurrentCount={0}", cde.CurrentCount);
                Console.WriteLine("IsSet={0}", cde.IsSet);
            }
        }
        
        void TaskProc(object data)
        {
            Console.WriteLine("Task ID={0} 開始", Task.CurrentId);
            Thread.Sleep(TimeSpan.FromSeconds(new Random().Next(10)));
            
            //
            // 既に3つ終了しているか否かを確認し、まだならシグナル.
            //
            CountdownEvent cde = data as CountdownEvent;
            if (!cde.IsSet)
            {
                cde.Signal();
                Console.WriteLine("***カウントをデクリメント*** Task ID={0} CountdownEvent.CurrentCount={1}", Task.CurrentId, cde.CurrentCount);
            }
            
            Console.WriteLine("Task ID={0} 終了", Task.CurrentId);
        }
    }
    #endregion


実行結果は以下のようになります。

  InitialCount=3
  CurrentCount=3
  IsSet=False
  Task ID=1 開始
  Task ID=2 開始
  Task ID=3 開始
  Task ID=4 開始
  ***カウントをデクリメント*** Task ID=4 CountdownEvent.CurrentCount=2
  Task ID=4 終了
  Task ID=5 開始
  ***カウントをデクリメント*** Task ID=5 CountdownEvent.CurrentCount=1
  Task ID=5 終了
  ***カウントをデクリメント*** Task ID=3 CountdownEvent.CurrentCount=0
  Task ID=3 終了
  5つのタスクの内、3つ終了
  メインスレッド 続行開始・・・
  Task ID=2 終了
  Task ID=1 終了
  全てのタスク終了
  InitialCount=3
  CurrentCount=0
  IsSet=True


指定した数分終了した後、メインスレッド側の待機が解除されているのが分かります。



================================
過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。