LoginSignup
2
1

C#のTimerでハマったメモ

Posted at

C#のTimerは4種類ある

この記事を読んで
「ほーんとりあえずSystem.Timers.Timer使っとけばOKみたいやな」
って思ってたらハマったのでメモ。

注:自分もまだ原理を理解しきれていないのであやふやな書き方をしている

結論

WindowsFormなら、System.Windows.Forms.Timerを使おう

元のソース

View
public partial class View : Form, IView
{
    Presenter presenter;
    
    public View()
    {
        InitializeComponent();
        presenter = new Presenter(this);
    }

    // デザイナーで追加したタイマー
    Timer IView.timer { get => winFormTimer; }

    // タイマー作動時
    private void winFormTimer_Tick(object sender, EventArgs e)
    {
        // プレゼンターのメソッドを呼ぶだけ
        presenter.timer_Tick();
    }

    public void UpdateChart(Point[] points)
    {
        // 引数からグラフを更新する(割愛)
    }
}
Presenter
class Presenter
{
    private IView view;

    public Presenter(IView _view)
    {
        view = _view;
    }

    public void timer_Tick()
    {
        // 外部と通信

        // 通信データを使ってグラフの描画点の配列を作成
        var points = new Point[30];

        // Viewのグラフ更新メソッドに渡す
        view.UpdateChart(points);
    }

    // 他にも必要に応じてtimerを止めたり動かしたりしてる
}

うーん…このtimer、プレゼンターでしか使っとらんし、System.Windows.Forms.Timerは精度良くないらしいし、ここはPresenterにSystem.Timers.Timerを置く形に変更してみよ!

変更後

View
public partial class View : Form, IView
{
    Presenter presenter;
    
    public View()
    {
        InitializeComponent();
        presenter = new Presenter(this);
    }

    public void UpdateChart(Point[] points)
    {
        // 引数からグラフを更新する(割愛)
    }
}
Presenter
class Presenter
{
    private IView view;

    private System.Timers.Timer timer;

    public Presenter(IView _view)
    {
        view = _view;

        timer.Elapsed += timer_Tick;
    }

    public void timer_Tick(object sender, EventArgs e)
    {
        // 外部と通信処理

        // 通信データを使ってグラフの描画点の配列を作成
        var points = new Point[30];

        // Viewのグラフ更新メソッドに渡す
        view.UpdateChart(points);
    }

    // 他にも必要に応じてtimerを止めたり動かしたりしてる
}

結果:「外部と通信処理」の箇所で
「メッセージ フィルターはアプリケーションがビジーであることを示しています。」
って言われまくる

なんで?

ぶっちゃけよくわかってない。
なんとなくの理解で書くと…

  • 通信処理はViewと同じスレッドで動く
  • 通信処理には個数制限(セマフォ的な?)がある
  • 通信処理とtimerが同じスレッドで動く場合、timerは通信処理と同期して動く
  • そのため、個数制限があふれることはない
  • 通信処理とtimerが別スレッドで動く場合、個数制限に関係なくタイマーが動く
  • そのため、個数制限に関係なくタイマーは通信を要求し続け、結果アプリケーションがビジーになる

多分こう。

対策

おとなしくSystem.Windows.Forms.Timerを使うと元に戻った。
あるいは、System.Timers.TimerSynchronizingObjectプロパティにViewを設定してもいいらしい。

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1