在后台线程中运行计时器

本文关键字:运行 计时器 线程 后台 | 更新日期: 2023-09-27 17:59:55

我正在寻找一种在后台线程中使用System.Windows.Forms.Timer的方法。我很难在后台线程中启动和停止它。这就是我正在做的:

private System.Windows.Forms.Timer chkTimer = new System.Windows.Forms.Timer();

然后在backgroundworker_dowork方法中,我有这样的:

     chkTimer.Interval = 2000;
     chkTimer.Tick += new EventHandler(chkTimer_Tick);
     chkTimer.Start();

在Tick方法中,我有与计时器相关的代码,但由于某种原因,它不会运行。如果我在ui线程中声明以上内容,它就会工作。有人能帮我在后台启动计时器吗?我不想使用系统计时器,所以请不要建议

感谢

在后台线程中运行计时器

using System.Timers;
using System.Threading.Tasks;
.
.
.
var timer = new Timer(250);
.
.
.
private void Initialize()
{
    timer.Elapsed += (o, s) => Task.Factory.StartNew(() => OnTimerElapsed(o, s));
    timer.Start();
}
.
.
.
private void OnTimerElapsed(object o, ElapsedEventArgs s)
{
    //Do stuff
}

如果需要,还可以去掉OnTimerElpsed参数"o"answers"s"。

Forms的计时器通过将消息发布到表单的句柄消息来工作,然后必须由表单的消息循环来处理这些消息。后台线程(通常)没有消息循环,因此WM_Timer消息在发布时不会去任何地方(回调没有被调用)。

使用System.Timers有什么问题?

我不会完全使用计时器,这是额外的负担。根据我所读到的内容,您希望有两个线程,UI和后台线程。

因此,让后台线程来管理间隔,而不是计时器。

Psuedo代码:

YourFileChecker checker = new YourFileChecker();
checker.CheckInterval = 60000; //milliseconds, the background thread will manage the interval
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(checker.Check));
t.Start();

然后让Check方法做这样的事情:

 while(!_Stop)
 {
      //Do your work here
      //Wait the specified interval before checking again...
      Thread.Sleep(_CheckInterval);
 }

后台线程现在只是不断地检查,直到它被告知(发出信号)停止。然后,您根本不需要计时器,因为线程正在管理间隔。

来自文档:

Windows窗体计时器组件是单线程的,精度限制为55毫秒。如果需要更高精度的多线程计时器,请使用System.Timers命名空间中的timer类。

System.Windows.Forms名称空间中的大多数组件都不是为在后台线程上运行而设计的。

您应该只使用BackgroundWorker。启用BackgroundWorker属性WorkerSupportsCancellation。在DoWork方法中添加:

while(!yourBGWorker.CancelationPending)
{
   //Do some work
   Thread.Sleep(2000);
}

它做你想做的事情——在后台线程中做一些工作,并等待指定的时间段。您也可以在调用yourBGWorker.CancelAsync(); 后取消进度

System.Windows.Forms.Timer完全基于Win32消息,因此需要消息循环。换句话说,它只能在UI线程上运行。另一种选择是System.Threading.Timer,它将在一个单独的线程中打勾,但您提到它对您不起作用。据我所知,没有办法创建一个将调度到任意线程的计时器(不过,您可以自己进行调度)。从技术上讲,可以在线程中启动第二个消息循环,并在那里运行Windows窗体计时器,但我不建议这样做(您需要泵送消息等)。通常有更好的方法可以做到这一点。

我最近写了一篇文章,可能正是您想要的。它在c#中演示了一个通用的轮询组件,该组件以指定的间隔运行,并使用后台线程执行指定的用户操作。您可以在主线程上启动它,以便在辅助线程上运行事件。

示例用法:

IPoller poller = new UrlPoller(args[0], TimeSpan.FromSeconds(7));
IPolling pollingComponent = new Polling.Core.Polling(poller);
pollingComponent.SubscribeForPollingUpdates(PollingAction);
pollingComponent.Start();

对于代码和完整用法:

http://www.avantprime.com/blog/24/an-example-of-repeating-code-using-a-worker-thread-without-using-timers-c