0

マルチスレッド アプリケーションでいくつか使用System.Threading.Timer(s)していますが (実際には 3 つのタイマーを使用しています)、非常にうまく機能しているにもかかわらず、やり方が間違っていて、不要なリソースを消費しているように感じます。実際には、私がやっていることはこれです:

  1. アプリケーションのメイン ウィンドウ (WPF ウィンドウですが、それほど重要ではないと思います) で、3 つのスレッドを開きます。

  2. これら 3 つのスレッドのそれぞれで、3 つのタイマーの 1 つを初期化して開始します。

これを行うために 3 つの異なるスレッドを使用している理由は、どこかで読んだことを覚えているためです (場所が見つかりません) System.Threading.Timer。タイマー開始時)。

さて、次の単純なアプリケーションをテストしましたが、Timer とそれを開始するスレッドとの間に競合はないようです。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    System.Threading.Timer _t1, _t2, _t3;

    private void Form1_Load(object sender, EventArgs e)
    {
        _t1 = new System.Threading.Timer(new TimerCallback(_t1Run),
                           null, TimeSpan.Zero, TimeSpan.FromMilliseconds(15));
        _t2 = new System.Threading.Timer(new TimerCallback(_t2Run),
               null, TimeSpan.Zero, TimeSpan.FromMilliseconds(35));
        _t3 = new System.Threading.Timer(new TimerCallback(_t3Run),
               null, TimeSpan.Zero, TimeSpan.FromMilliseconds(150));

        for (int i = 1; i <= 5000; i++)
        {
            Console.WriteLine("Writting on main form " + i);
        }
    }

    void _t1Run(object State)
    {
        _t1.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
        Console.WriteLine("running 1");
        _t1.Change(TimeSpan.FromMilliseconds(15), TimeSpan.FromMilliseconds(15));
    }

    void _t2Run(object State)
    {
        _t2.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
        Console.WriteLine("running 2");
        _t2.Change(TimeSpan.FromMilliseconds(35), TimeSpan.FromMilliseconds(35));
    }

    void _t3Run(object State)
    {
        _t3.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
        Console.WriteLine("running 3");
        _t3.Change(TimeSpan.FromMilliseconds(150), TimeSpan.FromMilliseconds(150));
    }

}

では、メイン ウィンドウで 3 つのタイマーをすべて開始できますか (または別のスレッドが必要ですか)。これが問題を引き起こさないことを誰かが確認できますか (私がテストしたアプリケーションでは問題がないように見えるため)。

編集: 3 つのタイマーには異なる目的があり、そのうちの 2 つは実際にはいくつかの UI 相互作用を持っています (1 つはメイン ウィンドウと相互作用し、もう 1 つはセカンダリ ウィンドウと相互作用します - 3 つ目はバックグラウンド操作のみを行います)。使用System.Windows.Forms.Timerは、タイマーが多くの操作を行うことであり、メインスレッドでこれらすべての操作を行う場合、すべての GUI 対話を実際にブロックするよりも (私はこれらのタイマースレッドを 100 ~ 200 ミリ秒の間隔で呼び出すので、想像 ...) 。これは、タイマーによって呼び出されたスレッドから GUI の対話を行う方法の例です。

MainWindow.ThisInstance.TitleLabel.Dispatcher.BeginInvoke((Action)(() => UpdateMainWindow_TimeLabel(TimeLabelValue)));
4

1 に答える 1

4

タイマー コールバック コードにある種の UI 要素の相互作用がある場合は、System.Windows.Forms.Timer代わりに使用する必要があります。System.Threading.Timer

System.Threading.Timer は、タイムスパンが経過するたびにスレッドプール スレッドをスピンアウトします。ただし、フォーム要素はスレッドセーフではないため、これにより問題が発生する可能性があります。専用の UI スレッド以外のスレッドを使用して UI 要素にアクセスすると、望ましくない結果が生じる可能性があります。

このスレッドの安全でない動作を克服するには、System.Windows.Forms.Timer を使用する必要があります。System.Windows.Forms.Timer は、新しいスレッドを作成したり、新しいスレッドプール スレッドをスピンしたりしません。UI スレッドでタイマー コールバックを実行するだけです。このようにして、すべての UI 対話が単一のスレッドで実行され、スレッド セーフが保証されます。

ただし、タイマー コールバックが完了するまでにかなりの時間がかかる場合、UI がフリーズするため、System.Windows.Forms.Timer は非常に短いタスクにのみ使用する必要があります。より長いバックグラウンド タスクの場合は、使用できますSystem.ComponentModel.BackgroundWorker

于 2013-08-03T20:33:48.257 に答える