OSDN Git Service

FDK の実装を完了。
[strokestylet/CsWin10Desktop3.git] / FDK24 / カウンタ / 定間隔進行.cs
1 using System;
2 using System.Collections.Generic;
3
4 namespace FDK.カウンタ
5 {
6         /// <summary>
7         /// 一定間隔ごとの進行処理を実現するクラス。
8         /// </summary>
9         /// <remarks>
10         /// <para> 例えば、
11         /// <code>
12         ///   var cf = new C定間隔進行();
13         ///   cf.経過時間の分だけ進行する( 400, 定間隔処理 );
14         /// </code>
15         /// と記述した場合、400ms ごとに 定間隔処理() が実行されるようになる。
16         /// </para>
17         /// <para>
18         /// ただし、この動作は「経過時間の分だけ進行する()」メソッドを呼び出した時に、定間隔処理() を「必要な回数だけ反復実行」する仕様である。
19         /// 例えば、先述の例において、メソッドの呼び出し時点で、前回の同メソッド(またはコンストラクタ)の呼び出しから 900ms が経過していたとすると、
20         /// 定間隔処理() は 900÷400 = 2回実行され、残りの 100ms が経過時間として次回に繰り越される。
21         /// (一回の処理に時間がかかった場合にも定間隔処理が並列実行されるわけではない。)
22         /// </para>
23         /// <para>
24         /// なお、定間隔処理にラムダ式を使用する場合は、キャプチャ変数のライフサイクル(実行される時点でまだ存在しているか否か)に留意し、弱い参照 の利用も検討すること。
25         /// </para>
26         /// </remarks>
27         public class 定間隔進行
28         {
29                 /// <summary>
30                 /// コンストラクタ。初期化と同時に、間隔の計測も開始する。
31                 /// </summary>
32                 public 定間隔進行()
33                 {
34                         this.経過時間の計測を開始する();
35                 }
36                 public void 経過時間の計測を開始する()
37                 {
38                         lock( this.排他利用 )
39                         {
40                                 this.Timer.リセットする();
41                         }
42                 }
43                 public void 経過時間の計測を一時停止する()
44                 {
45                         lock( this.排他利用 )
46                         {
47                                 this.Timer.一時停止する();
48                         }
49                 }
50                 public void 経過時間の計測を再開する()
51                 {
52                         lock( this.排他利用 )
53                         {
54                                 this.Timer.再開する();
55                         }
56                 }
57                 public void 経過時間の分だけ進行する( long 間隔ms, Action 定間隔処理 )
58                 {
59                         lock( this.排他利用 )
60                         {
61                                 // 現在時刻を取得。
62                                 this.Timer.現在のカウントをキャプチャする();
63                                 long 現在時刻ms = this.Timer.現在のキャプチャカウント100ns単位 / 10000;
64
65                                 // 初めての進行の場合、前回時刻を初期化する。
66                                 if( QPCTimer.未使用 == this.前回の進行時刻ms )
67                                 {
68                                         this.前回の進行時刻ms = 現在時刻ms;
69                                 }
70
71                                 // (ないと思うが)タイマが一回りしてしまった時のための保護。正常動作を保証するものではない。
72                                 if( 現在時刻ms < this.前回の進行時刻ms )
73                                 {
74                                         this.前回の進行時刻ms = 現在時刻ms;
75                                 }
76
77                                 // 経過時間における回数だけ、処理を実行する。
78                                 while( ( 現在時刻ms - this.前回の進行時刻ms ) >= 間隔ms )
79                                 {
80                                         定間隔処理();
81                                         this.前回の進行時刻ms += 間隔ms;
82                                 }
83                         }
84                 }
85
86                 private long 前回の進行時刻ms = QPCTimer.未使用;
87                 private readonly QPCTimer Timer = new QPCTimer();
88                 private readonly object 排他利用 = new object();
89         }
90 }