计时器在不同于创建它的线程中运行

本文关键字:线程 运行 不同于 创建 计时器 | 更新日期: 2023-09-27 18:29:17

使用Visual Studio 2015,可视化C#窗口应用程序。

我需要一个清空主线程中队列的计时器,因为一些UI组件被修改了。我编码了这个:

    public Form1()
    {
        InitializeComponent();
        Q = new ConcurrentQueue<amsg>();
        timer = new System.Timers.Timer(100);
        timer.Elapsed += timer_Elapsed;
        timer.Enabled = true;
    }
    void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        clsUdpMsg msg;
        while (Q.TryDequeue(out msg)) handleRx(msg);
    }

但是Elapsed事件在工作线程中执行。。。?

如果我在设计时在主窗体上放一个计时器,生成的原型会略有不同:

    private void timer1_Tick(object sender, EventArgs e)
    {
        amsg msg;
        while (Q.TryDequeue(out msg)) handleRx(msg);
    }

但是这个确实在主线程上下文中执行。

这个问题延伸到任何以这种方式创建计时器的线程;我认为在线程中创建的计时器会在同一线程上下文中执行经过的事件。我是不是错过了什么?

快速编辑:我看到了不同的定时器,System.timers.Timer和Windows.Forms.Timer。那么,我如何可靠地创建将在创建它们的线程中执行的定时器?

计时器在不同于创建它的线程中运行

是的,您只处理两个独立的Timer类。System.Windows.Forms.Timer在主线程上激发其Tick事件,而System.Timers.Timer在后台线程上激发它的Elapsed事件。System.Windows.Forms.Timer的优点在于它隐藏了线程;CCD_ 7的优点是它不需要消息泵来工作。

你会问,"我如何可靠地创建将在我创建计时器的线程中执行的计时器?"好吧,当你有Windows窗体GUI并在UI线程上启动计时器时,这很容易:只需使用System.Windows.Forms.Timer。如果你没有消息泵可以利用,你必须使用System.Timers.Timer,并且当计时器触发其Elapsed事件时,在主线程上运行某些东西的唯一方法基本上是在主线程中重新创建类似消息循环的东西——让它停下来,也许等待来自计时器线程的Monitor.Pulse或其他类型的通知。但这意味着你的主线程在此期间不会得到任何有用的东西。。。

这不是对您问题的直接回答,而是一个避免计时器线程问题的建议。

你可以一直使用微软的反应式框架(NuGet"Rx-WinForms")。

你的代码看起来是这样的:

var subject = new Subject<clsUdpMsg>();
var subscription =
    subject
        .ObserveOn(this)
        .Subscribe(msg => handleRx(msg));

subject将取代您的Q。每当您想添加消息时,只需拨打subject.OnNext(msg)即可。

即使对subject.OnNext(msg)的调用是在后台线程上进行的,.ObserveOn(this)也会将调用编组回UI。

如果您想停止订阅,请致电subscription.Dispose()