2

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

Suman Banerjee
  • 1,923
  • 4
  • 24
  • 40
Greg
  • 71
  • 1
  • 4
  • 9

7 Answers7

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.

user1172282
  • 527
  • 1
  • 9
  • 19
  • very simple and elegant solution. no need to mess around with background workers, or let your main task run on a different thread. – Peet Jun 07 '18 at 16:25
  • Without the LongRunning flag passed to StartNew(), this 1) uses a thread pool thread, so it might start delayed waiting for a thread to become available, and 1) the thread won't be a background thread. – Chris Bordeman Aug 08 '20 at 11:15
2

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?

  • Is there a way to run a systyem.timer within the backgrounding thread and not create its own? – Greg Jun 22 '11 at 20:21
  • No. A system timer runs on the default thread pool. If you had a timer local to the thread you would have to poll for it or block on an event, waiting for it to fire, since nothing can interrupt the thread while it's running. The equivalent of this would be sleeping in the thread. Can you explain what you're trying to accomplish? – 500 - Internal Server Error Jun 22 '11 at 20:26
  • 1
    Clarification: the callback from a system timer runs on a thread pool thread. – 500 - Internal Server Error Jun 22 '11 at 20:29
  • I really dont understand the above. But what i am trying to do is this. I need to check a folder for some txt files as they appear. I need only 2 threads to be running as part of the restriction of the program that is out of my hands. One of them has to be backgrounder and one has to be ui. I need a timer inside backgrounder that checks the folder for files every x min. I cannot have 3 threads. – Greg Jun 22 '11 at 20:47
  • Then simply use a Sleep in your thread as another poster suggests. – 500 - Internal Server Error Jun 22 '11 at 22:07
  • The sleep causes the same problem im having with using a system.timer. – Greg Jun 23 '11 at 13:08
  • If you are checking for files to appear, forget everything you have been told, simply use a FileSystemWatcher, its instant and has no loops or overhead, it just hooks the file system events... Don't try to reinvent the wheel. – Wobbles Mar 24 '15 at 20:09
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.

Jon Raynor
  • 3,804
  • 6
  • 29
  • 43
  • This also causes the application to fail to terminate while your thread is sleeping. The question was how to create a *background* thread, which will not block application exit. – Chris Bordeman Aug 08 '20 at 11:18
1

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.

Tim Rogers
  • 21,297
  • 6
  • 52
  • 68
1

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

Saurav Rastogi
  • 9,575
  • 3
  • 29
  • 41
Renatas M.
  • 11,694
  • 1
  • 43
  • 62
  • 1
    But occupying a Pool thread for a longer period is a bad idea. And real programs don't Sleep(). – H H Jun 23 '11 at 06:32
  • What if you need to cancel the worker during the Sleep period? – noahnu May 16 '13 at 14:43
  • And what if the app needs to exit during the sleep? – Chris Bordeman Aug 08 '20 at 11:20
  • @ChrisBordeman then you can add very small sleep time and a counter. When counter elapses - do work... Although I would not suggest to use this (my 9 year old) answer :). Check https://stackoverflow.com/a/14594558/754438 answer - let the timer fire a background work and cancel timer when you want. – Renatas M. Aug 13 '20 at 13:09
0

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

0

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.

fparadis2
  • 913
  • 7
  • 12
  • Basically, the problematic lies in the fact that for a timer to attach to an arbitrary thread, it would require a way to _dispatch_ code (or _invoke_) to an arbitrary thread. There is no general way to do this. Usually, dispatching is done using the message loop (Win32/WinForms), a Dispatcher (WPF) or a custom mechanism. – fparadis2 Jun 22 '11 at 20:28