Timer is not working in cross threads - c#

I have 2 global System.Windows.Forms.Timer in my form. Both are initialized in form's constructor. But not started yet. Constructor starts a new thread and that thread enables and starts both of the timers. Obviously it is all cross threading, but it doesn't throw any cross-thread exception. But it doesn't even work. It does not fire the Timer.Tick method. Here is the code:
1st Method:
In form constructor:
KeepMeAliveTimer = new Timer(); //timer 1
KeepMeAliveTimer.Interval = 15000;
KeepMeAliveTimer.Tick += KeepMeAlive;
timer1 = new Timer(); //timer 2
timer1.Interval = 15000;
timer1.Tick += timer1_Tick;
//started a new thread
In new thead:
//after performing some tasks, it enables the timers
KeepMeAliveTimer.Enabled = true; //timer 1
KeepMeAliveTimer.Start();
timer1.Enabled = true; //timer 2
timer1.Start();
But it is not firing up Timer's tick events and not even throwing any exception.
2nd Method:
But when I initialized and enabled the Timers in the same thread (Main Thread) they are working perfectly:
KeepMeAliveTimer = new Timer(); //timer 1
KeepMeAliveTimer.Interval = 15000;
KeepMeAliveTimer.Tick += KeepMeAlive;
KeepMeAliveTimer.Enabled = true;
KeepMeAliveTimer.Start();
timer1 = new Timer(); //timer 2
timer1.Interval = 15000;
timer1.Tick += timer1_Tick;
timer1.Enabled = true;
timer1.Start();
Now the question is; Why the first method is not working if there is not even any exception?

The Timer class is thread-safe but not in the way you expect it. Calling the Start() method on worker thread does actually start the timer. The class goes through the effort of creating a hidden window so it can call the SetTimer winapi function and receive the WM_TIMER message when it is done.
But the Tick event cannot be raised if nobody is listening for that message. You won't be, surely you didn't call Application.Run() on that thread. You should therefore not start a timer on a worker thread. Use Control.BeginInvoke if necessary to get it started on the UI thread.
Or use a System.Threading.Timer or System.Timers.Timer, they don't depend on a message loop. You do have to interlock properly, their Elapsed event or callback run on yet another thread. Which is the kind of solution that tends to create another problem.

Related

C# and how to use "System.Timers"

I recently started to use C# and I wanted to use timers.
I read Windows help about how to declare and define a Timer.
What I don't understand is why I need the Console.ReadLine(); line to start the timer.
(Link to the example)
// Firstly, create a timer object for 5 seconds interval
timer = new System.Timers.Timer();
timer.Interval = 5000;
// Set elapsed event for the timer. This occurs when the interval elapses −
timer.Elapsed += OnTimedEvent;
timer.AutoReset = false;
// Now start the timer.
timer.Enabled = true;
Console.ReadLine(); // <------- !!!
What I want to do but I don't achieve is to start the timer as soon as it is declared. I dont want to write Console.ReadLine(); because I may not need a console.
Example: If i develop a timer class and I call it from an other class, how can I check the timer has been completed?
Thank you in advance.
You need to set Timer, than wait for time is elapsed which executes the OnTimedEvent, that is how you can check if it already elapsed.
// Create a timer with a two second interval.
timer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
timer.Elapsed += OnTimedEvent;
timer.AutoReset = true;
timer.Enabled = true;
The OnTimedEvent should look like this:
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
e.SignalTime);
}
If you need to Stop the timer you should call:
timer.Stop();
timer.Dispose();
You need Console.ReadLine(); just for not exiting the main method and the whole program. If you're developing something else like MVC or WPF, you don't need it.

.Net: how to wait until System.Timers.Timer stops

I have a System.Timers.Timer instance created in the main thread. Now I call timer.Stop() to try to terminate that time and want to wait until the timer is really terminated. How could I do that?
Is there any similar method like System.Threading.Thread.Join()?
Here are some codes
//the main thread:
var aTimer = New Timer();
aTimer.Elapsed += SomeTimerTask;
aTimer.AutoReset = True;
aTimer.Start();
//some other logic...
//stop that timer:
aTimer.Stop();
//now I need to wait until that timer is really stopped,
//but I cannot touch the method SomeTimerTask().
//so I need something like System.Threading.Thread.Join()...
You could make use of a ResetEvents which are wait handles which can block a thread until you set the state to signaled:
class TimerAndWait
{
private ManualResetEvent resetEvent = new ManualResetEvent(false);
public void DoWork()
{
var aTimer = new System.Timers.Timer(5000);
aTimer.Elapsed += SomeTimerTask;
aTimer.Elapsed += ATimer_Elapsed;
aTimer.AutoReset = true;
aTimer.Start();
// Do something else
resetEvent.WaitOne(); // This blocks the thread until resetEvent is set
resetEvent.Close();
aTimer.Stop();
}
private void ATimer_Elapsed(object sender, ElapsedEventArgs e)
{
resetEvent.Set();
}
}
If you want a async/task-based solution you have to use the ThreadPool.RegisterWaitForSingleObject method
The Timer does not fire up the Elapsed when you call stop as you can read in the docs of the Stop()-Method:
Stops raising the Elapsed event by setting Enabled to false.
The Elapsed-Event is only triggered when the Timers Enabled-Property is set to true and the given Interval (which you have to set) is elapsed (this can happen multiple times).
So if you stop your Timer before the Interval is elapsed, you might have to trigger your code in some other way.

BackgroundWorker Suspend

I have a BackgroundWorker _worker
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
_timer = new System.Timers.Timer();
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
_timer.Interval = 5000;
_timer.Start();
}
When it gets to the line _timer.Start() it thinks it has finished so fires the RunWorkerCompleted event.
I don't want it to finish until the _timer.Interval time has been reached and the _timer Elapsed event has been trigger:
void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
for (int i = 1; i < 20; i++)
{
if (listBox1.InvokeRequired)
listBox1.Invoke((Action)(() => listBox1.Items.Add("Do Things Thread")));
else
listBox1.Items.Add("Do Things Completed");
_worker.ReportProgress((int)(((decimal)i / (decimal)20) * 100));
Thread.Sleep(1000);
}
_timer.Stop();
}
Because I need the BackgroundWorker to report back some progress.
How do I do this. I need it to run on a different thread.
So to round up the discussion and the solution.
System.Timers.Timer will automatically thread the timer event for you unless you supply a sync object, as discussed in MSDN:
If the SynchronizingObject property is null, the Elapsed event is
raised on a ThreadPool thread. If processing of the Elapsed event
lasts longer than Interval, the event might be raised again on another
ThreadPool thread. In this situation, the event handler should be
reentrant.
This means that the background worker becomes superfluos. You can simply have your timer event code run as is (as it uses invoke to interact with the UI anyhow).
It does mean that these events can run concurrently if they take a long time. However, you can of course stop and start the timer in the event callback.
Your _timer_Elapsed event is on a different thread. The instance of timer will expire as soon as the control flow passes through the _worker_DoWork function. The scope of your timer object variable is restricted to the function and hence it will not work this way.
I would suggest that you put put Thread.sleep(5000) in the timer _worker_dowork function itself. It will not affect your application as the thread will sleep and the gui will still be responsive.
I think, just by playing around with what I've done, is that I've invoked the progress bar, so I don't need the ReportProgress:
_worker.ReportProgress((int)(((decimal)i / (decimal)20) * 100));
Changed to :
if (progressBar1.InvokeRequired)
progressBar1.Invoke((Action)(() => progressBar1.Value = (int)(((decimal)i / (decimal)20) * 100)));
else
progressBar1.Value = (int)(((decimal)i / (decimal)20) * 100);
That means, I don't have to suspend the BackgroundWorker, and the timer was invoked on a different thread and will remain until disposed of????

Windows Forms Timer doesn't stop. How is that possible?

During debugging I can see that after Timer.Stop() or Timer.Enabled = false commands are executed, Timer is still running (Timer.Enabled = true). How is that possible?
This is possible when you stop the timer on a worker thread. For example:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
Timer timer1;
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
timer1 = new Timer();
timer1.Interval = 3000;
timer1.Start();
var t = new System.Threading.Thread(stopTimer);
t.Start();
}
private void stopTimer() {
timer1.Enabled = false;
System.Diagnostics.Debug.WriteLine(timer1.Enabled.ToString());
}
}
Output:
True
The timer must be stopped by the UI thread, the class takes care of it automatically. Quite similar to Control.BeginInvoke(). There's an explicit race, the Tick event handler can run after you stopped it. This can also happen on the UI thread if the very first timer you create is created on a worker thread. A splash screen for example. That's not healthy, you ought to fix that.
Calling Start after you have disabled a Timer by calling Stop will cause the Timer to restart the interrupted interval. If your Timer is set for a 5000-millisecond interval, and you call Stop at around 3000 milliseconds, calling Start will cause the Timer to wait 5000 milliseconds before raising the Tick event.
bear also in mind
Calling Stop on any Timer within a Windows Forms application can cause messages from other Timer components in the application to be processed immediately, because all Timer components operate on the main application thread. If you have two Timer components, one set to 700 milliseconds and one set to 500 milliseconds, and you call Stop on the first Timer, your application may receive an event callback for the second component first. If this proves problematic, consider using the Timer class in the System.Threading namespace instead.
http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.stop.aspx
public void EnableTimer(bool state)
{
if (this.InvokeRequired) {
this.Invoke(new Action<bool>(EnableTimer), state);
} else {
this.Timer1.Enabled = state;
}
}
Try this code...

background timer working only in one thread C#

I have a kinda awkward problem, I'm working with C# and WPF in .NET 4.0 and what I need is a timer that will create only one thread but it will need to work in the background, so not in the main thread, the problem is using System.Windows.Forms.Timer or DispatchTimer will automatically force it to work on the main thread and be influenced by the UI, on the other side using System.Timers.Timer or System.Threading.Timer will create a new thread for every cycle that overpasses the time interval, this will happen since the code in the elapsed timer event is a bit big, although part of it is sent further to a background worker.
so I was thinking if it's possible to force, say the System.Timers.Timer, to work in the background and never spawn to more then one thread, also I am opened to other suggestions
Use System.Timers.Timer, which fires its elapsed event handler on a ThreadPool thread. As soon as you enter the event handler, stop the timer. At the end of your event handler, start the timer and it will start counting down from the beginning of its interval.
Here's a simple example with a 100ms timer that spends 2 seconds in it's elapsed event handler:
static void Main(string[] args)
{
System.Timers.Timer myTimer = new System.Timers.Timer(100);
myTimer.Elapsed += new System.Timers.ElapsedEventHandler(myTimer_Elapsed);
myTimer.Start();
Console.ReadLine();
}
static void myTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
((System.Timers.Timer)sender).Stop();
Console.WriteLine(DateTime.Now.ToString("HH.mm.ss"));
System.Threading.Thread.Sleep(2000);
((System.Timers.Timer)sender).Start();
}
Just use a System.Threading.Timer with a period of 0 so that the callback runs only once. When everything is done, recharge the timer so it will fire again later. You'll have guaranteed only ever one thread running this way.
DispatcherTimer has a constructor overload that lets you do exactly what you want.
Use it in the context of your thread:
using System.Threading;
using WpfThreading = System.Windows.Threading;
...
Thread t = new Thread(() =>
{
var interval = TimeSpan.FromSeconds(3.0);
var priority = WpfThreading.DispatcherPriority.Background;
EventHandler callback = (a, e) => { };
var dispatcher = WpfThreading.Dispatcher.CurrentDispatcher; // dispatcher for this thread
WpfThreading.DispatcherTimer dt = new WpfThreading.DispatcherTimer(interval, priority, callback, dispatcher);
bool sameDispatchers = WpfThreading.Dispatcher.CurrentDispatcher == this.Dispatcher; // false
});
t.Start();

Categories