Run timer in background thread

2019-05-29 04:14发布

问题:

Im looking for a way to use a System.Windows.Forms.Timer within a backgrounder thread. I cam having a lot of trouble getting it to start and stop within the background thread. This is what i am doing:

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

Then in the backgroundworker_dowork method i have this:

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

In the Tick method i have the timer related code but it will not run for some reason. If i declare the above in the ui thread, it works. Can someoine please help me start the timer within the background thread? I do not want to use System.Timers so please dont suggest that

Thanks

回答1:

Forms' timer works by posting messages to the form's handle - messages, which must then be processed by the form's message loop. Background threads (usually) don't have message loops so the WM_Timer message, while being posted, doesn't go anywhere (your callback isn't being invoked).

What's wrong with using System.Timers?



回答2:

I would not use a timer altogether, its extra baggage. From what I read you want to have two threads, the UI and the background thread.

So, have the background thread manage the interval instead of the timer.

Psuedo Code:

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();

Then have the Check method do something like this:

 while(!_Stop)
 {
      //Do your work here

      //Wait the specified interval before checking again...
      Thread.Sleep(_CheckInterval);
 }

The background thread now just keeps checking until it is told (signaled) to stop. Then you don't need the timer at all because the thread is managing the interval.



回答3:

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
}

You can also get rid of the OnTimerElapsed parameters "o" and "s" if you want.



回答4:

From the documentation:

The Windows Forms Timer component is single-threaded, and is limited to an accuracy of 55 milliseconds. If you require a multithreaded timer with greater accuracy, use the Timer class in the System.Timers namespace.

Most components in the System.Windows.Forms namespace are not designed to run on background threads.



回答5:

You should use just BackgroundWorker. Enable the BackgroundWorker property WorkerSupportsCancellation. In the DoWork method add:

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

It does what you want - do some work in background thread and wait for a specified time period. Also you can cancel progress after calling yourBGWorker.CancelAsync();



回答6:

System.Windows.Forms.Timer is based entirely on Win32 messages and as such requires a message loop. In other words, it can only run on the UI thread. An alternative is System.Threading.Timer, which will tick in a separate thread but you mention it won't work for you. As far as I know, there is no way to create a timer that will dispatch to an arbitrary thread (you can do the dispatching yourself however). Technically, it is possible to start a second message loop in your thread and run a Windows Forms timer there but I would not recommend it (you need to pump messages, etc). Usually there's a better way to do this.



回答7:

I have recently written an article that may be just what you are looking for. It demonstrates in c# a generic polling component that runs at a specified interval and uses a background thread to perform the user action specified. You can launch this on your main thread to run the event on a worker thread.

Sample usage:

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

For the code and complete usage:

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