I have a Timer (System.Timers.Timer) that triggers every 100ms.
I subscribe an Event Handler to the Timer and it works just fine:
public override void TimerEvent(object source, ElapsedEventArgs e)
{
lock (timerlock)
{
Timer.Stop();
...
Timer.Start();
}
}
I use the timerlock, so when I unsubscribe from the timer I can be sure I am not in the middle of my TimerEvent Method.
So then when I want to unsubscribe from the Timer I do this:
lock (timerlock)
{
Timer.Elapsed -= TimerEvent;
}
try
{
DoSomethingThatTakesUpToAMinute();
}
catch (Exception ex)
{
MessageBox.Show("...");
}
finally
{
Timer.Elapsed += TimerEvent;
}
But when I subscribe to the Timer again in the finally block, my program takes up to 15 seconds until the next timer Event is registered even tho the finally was already executed. Note that what I do between unsubsribing and resubscribing to the timer can take up to a Minute.
I can see in the console that there are About 5 Threads that end with error Code 0 after the finally block and once they all ended my TimerEvents are Triggered again.
Any ideas?
Related
While I using winforms app, each 5 minute I need to check data updates. I need to send request to few service then get response and update data in database. What's is the best practices to make on another thread (or task ?)? The program should not slow down.
I try to make with timer:
Init timer when program is running
public class Timer
{
private System.Timers.Timer timer;
private void InitTimer()
{
timer = new System.Timers.Timer(4000);
timer.Elapsed += ElapsedTime;
timer.Enabled = true;
}
private void ElapsedTime()
{
//send request and update data
}
}
The way you are doing it will work just fine. The documentation for Sytem.Timers.Timer says:
If the SynchronizingObject property is null, the Elapsed event is raised on a ThreadPool thread.
The SynchronizingObject property is null by default, so your Elasped event will run on a ThreadPool thread, not on the UI thread. That means it will not stop your application from responding to user input.
If there is a chance that ElapsedTime() will run longer than your interval, and you don't want the events overlapping, then you can set AutoReset to false and reset it manually at the end of ElapsedTime(). Just make sure that everything is wrapped in a try/catch block, otherwise the timer won't get reset if there's an exception. My code below shows how that would look.
You don't need to use async/await anywhere here. Since it won't be running on the UI thread, using asynchronous code won't really help you any. In a desktop app, it's not a big deal to have a separate (non-UI) thread wait.
public class Timer
{
private System.Timers.Timer timer;
private void InitTimer()
{
timer = new System.Timers.Timer(4000);
timer.Elapsed += ElapsedTime;
timer.AutoReset = false;
timer.Enabled = true;
}
private void ElapsedTime()
{
try {
//send request and update data
}
catch (Exception e)
{
//log the error
}
finally
{
//start the timer again
timer.Enabled = true;
}
}
}
I have created a windows service on VS.net C#
In the OnStart event I start a timer.
In side the timer I call a function called DO()
the process of the DO() function is very long ( takes more than hour)
The process suppose to go this way
Start Then call the time immediately but due to the timer interval need to wait another day
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("In OnStart.");
try
{
Timer timer = new Timer();
timer.Interval = 1000 * 60 *60 * 24;
timer.Elapsed += new ElapsedEventHandler(this.OnTimer);
timer.Start();
DO();
}
catch (Exception ex)
{
eventLog1.WriteEntry("ERROR (OnStart) : " + ex.ToString());
}
}
public void OnTimer(object sender, ElapsedEventArgs args)
{
DO();
}
private void DO()
{
// Some process takes an hour
}
When the service starts it stays an hour in "Starting"
Is there a way I can start my service DO() function immediatly once the service started but not from the OnStart event?
Presuming you left nothing out of your example, your timer elapsed method will run on the ThreadPool.
So I would change this line in OnStart
DO();
...with this line:
ThreadPool.QueueUserWorkItem(x => Do());
It has the same net effect of what would happen if the timer fired immediately and, more importantly, will not block on that line.
using System.Timers;
void CreateTimer()
{
myTimerObject = new Timer(5000);
myTimerObject.AutoReset = false;
myTimerObject.Elapsed += MyEventOnElapsed;
myTimerObject.Start();
}
void MyEventOnElapsed(object sender, ElapsedEventArgs e)
{
lock(aLockObject)
{
myTimerObject.Stop();
// Perform actions that can exceed the interval time set in the timer
myTimerObject.Start();
}
}
void MethodTrigerredToStopTimer()
{
lock(aLockObject)
{
myTimerObject.Stop();
}
}
In the above code, my elapsed event (MyEventOnElapsed) is going to take a while to complete and hence I had to use timer start and stop as part of that method. When MethodTriggeredToStopTimer is triggered, let's assume the code is at MyEventOnElapsed and reached lock, however the thread at MethodTriggerredToStopTimer wins the race and manages to get the lock, my timer will be stopped by the MethodTriggeredToStopTimer(). However once the lock is released, the execution pointer waiting at the lock(aLockObject) in MyEventOnElapsed will continue start/stop the timer indefinitely. How to handle timers in this situation?
If you want a definitive way to stop via a method call or trigger when managing a loop like this, you will need to maintain some boolean isStopped or similar:
boolean isStopped = false;
void CreateTimer()
{
myTimerObject = new Timer(5000);
myTimerObject.AutoReset = false;
myTimerObject.Elapsed += MyEventOnElapsed;
myTimerObject.Start();
}
void MyEventOnElapsed(object sender, ElapsedEventArgs e)
{
lock(aLockObject)
{
if (isStopped)
return;
myTimerObject.Stop();
// Perform actions that can exceed the interval time set in the timer
myTimerObject.Start();
}
}
void MethodTrigerredToStopTimer()
{
lock(aLockObject)
{
isStopped = true;
myTimerObject.Stop();
}
}
This would all be much neater in a nice little wrapper class, with the state variable named something like Enabled to avoid confusion with the naming similarities to the Timer's start and stop methods. Additionally, I would take a look at building this loop using Task, Task.Delay, and CancellationToken as well if you end up needing cross-platform support or want to handle things like cancellation during your long-running operation.
One option would be to ask the timer whether the Timer is enabled before stopping (disabling) it. That way, if MethodTrigerredToStopTimer is called it will realise it has been stopped on purpose, and not start it up again.
void MyEventOnElapsed(object sender, ElapsedEventArgs e)
{
lock(aLockObject)
{
if (myTimerObject.Enabled)
{ try
{
myTimerObject.Stop();
// Perform actions that can exceed the interval time set in the timer
}
finally
{
myTimerObject.Start();
}
}
}
}
The try finally is helpful in ensuring that the timer is restarted by the time you exit the lock (even if an exception is thrown).
I just bumped into this code and I don't understand it. Is there a reason to use this design instead of just re-running the elapsed code with AutoReset true?
private readonly Timer Timer = new Timer();
protected override void OnStart(string[] args)
{
Logger.InfoFormat("Starting {0}.", ServiceName);
try
{
// If Enabled is set to true and AutoReset is set to false, the Timer raises the Elapsed event only once, the first time the interval elapses.
Timer.AutoReset = false;
Timer.Elapsed += Timer_Elapsed;
Timer.Interval = Settings.Default.ScriptingStatusLifeTime;
Timer.Start();
}
catch (Exception exception)
{
Logger.ErrorFormat("An error has occurred while starting {0}.", ServiceName);
Logger.Error(exception);
throw;
}
}
/// <summary>
/// Whenever the Schedule Service time elapses - go to the ScriptingStatus table
/// and delete everything created earlier than 1 hour ago (by default, read from ScriptingStatusLifeTime)
/// </summary>
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
// ScriptingStatusLifeTime defaults to 60 minutes.
DateTime deleteUntil = DateTime.Now.AddMilliseconds(Settings.Default.ScriptingStatusLifeTime * -1);
Logger.InfoFormat("Clearing all ScriptingStatus entries with ControlDate before: {0}.", deleteUntil);
RemoteActivator.Create<RemoteScriptingStatus>().DeleteUntil(deleteUntil);
}
catch (Exception exception)
{
Logger.Error(exception);
}
finally
{
Timer.Start();
}
}
Furthermore, I'm looking for a memoryleak in this code.
I just read this post: If the autoreset is set to false, will my timer be disposed automatically? which seems to imply that my Timer object needs to be disposed of properly. I don't see any calls to Dispose in the current file. I'm wondering if this Timer_Elapsed event is also introducing a leak?
As I understand it, by having AutoReset to true, the timer event being fired can overlap where the time the event takes to execute goes beyond the timeout value.
For example, timeout of 10 seconds but a workload of a 1 minute.
However with AutoReset as false then the timer event will only fire once. You can restart the timer in your event and the timer can continue.
In the example this means the timer can fire after 10 seconds but if the event takes longer than 10 seconds there's no overlap, it will just re-start after the work is completed.
This is pretty much how I do it and also how you have it in your example code.
Addendum: The above is only true if you don't set a sync object, this is because the elapsed event is raised on the thread pool. If you set a sync object then I'd expect locking to block the elapsed event so that only one event can fire at a time.
My timer 'Elapsed' event fires twice when the program is started. The only assignment of the 'Elapsed' event handler is in 'Main' method. Is there something that I'm doing wrong?
//class level clock
public static System.Timers.Timer Clock;
static void Main(string[] args)
{
Clock = new System.Timers.Timer();
Clock.Elapsed += new ElapsedEventHandler(Clock_Elapsed);
Clock.AutoReset = false;
Clock.Interval = timerInterval; //this needs to be in milliseconds!
Clock.Enabled = true;
//run infinite loop until q is pressed
while (Console.Read() != 'q')
{}
}
static void Clock_Elapsed(object sender, ElapsedEventArgs e)
{
Clock.Stop();
//do some stuff
Clock.Start();
}
UPDATE:
The AutoReset provided by #fparadis2 fixed the firing twice. The base issue was that my timer interval was set to 30 milliseconds instead of 30000 milliseconds(30 seconds) so that the event was double firing.
If timerInverval is small enough, it might be possible that the Elapsed event is fired twice before you get the chance to stop the clock. You should do
Clock.AutoReset = false;
in order to be notified only once each time you start the timer.
As specified in the Timer Class documentation:
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.
You may also consider checking this pattern.