「C#の4つのTimerの用途と使い方」によると、C#にはタイマーが4つあるらしい。で、System.Timers.Timerを使うのがいいんじゃないということだが、その精度はどのぐらいあるのか調べてみようかとやってみた。
とりあえずできたソースコードがこれ。1msecのタイマーを作成し、そこでストップウォッチで測定した結果をリストに入れるというもの。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public partial class Form1 : Form { System.Timers.Timer timer = new System.Timers.Timer(); Stopwatch stopwatch = new Stopwatch(); public Form1() { InitializeComponent(); timer.Interval = 1; timer.Elapsed += new ElapsedEventHandler(MyClock); timer.Start(); } public void MyClock(object sender, ElapsedEventArgs e) { var text = String.Format("{0}",stopwatch.ElapsedMilliseconds); this.BeginInvoke((Action)(() => { listBox1.Items.Add(text); })); stopwatch.Restart(); } } |
C#のタイマーの精度
結果的には、14~16 msecあたりしか出てない感じだ。
「C#のSystem.Threading.Timerクラスの精度を確認する」によると、
HALは周期が16ms(ハードによっては10msとかもある)となっていて、その仕組み上に乗っている(と思われる)C#のタイマーの精度は前述の数値に依存するかなと。
とのこと。Windows API的には、WaitableTimerを使ったりtimeBeginPeriodたりで、どうやら1msecとかのタイマーもできるようだ。
タイマー内からのコントロール更新
タイマー内からBeginInvokeを使わずに直接リストに追加しようとすると、
System.InvalidOperationException: ‘有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール ‘listBox1′ がアクセスされました。’
なんてエラーが出る。Invokeでメインスレッドで処理しないといけないようだ。ちなみに、BeginInvokeをInvokeにすると終了時に
System.ObjectDisposedException: ‘破棄されたオブジェクトにアクセスできません。
オブジェクト名 ‘Form1′ です。’
というエラーが出る。Invoke途中でFormが終了するために、行き場がなくなるのだろうか。(その点、BeginInvokeなら、勝手にキャンセルされる?ので問題ないのだろうか、細かくはよくわかっていない)