How to properly stop a timer - c#

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).

Related

Windows Forms async await

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;
}
}
}

Task execution time higher than Timer execution time

I would like to clarify possible code implementaion in case if the code executing withing timerDoJob_Elapsed is getting longer that it should.
So all internal things are gonna be coruppted/canceled and etc when timer fires next time.
Is there any pattern for this kind of problem?
Any clue about make it more stable?
private void timerDoJob_Elapsed(object sender, ElapsedEventArgs e)
{
VeryLongTask1();
VeryLongTask2();
VeryLongTask3();
}
If you're using System.Timers.Timer, turn off AutoReset. Then re-enable the timer at the end of your Elapsed method.
private void timerDoJob_Elapsed(object sender, ElapsedEventArgs e)
{
VeryLongTask1();
VeryLongTask2();
VeryLongTask3();
mytimer.Enabled = true;
}
This way, the timer does not even start again until the task is complete. But make sure to wrap everything in your Elapsed method in try/catch blocks because if an unhandled exception happens there, your timer won't start again.
Another method I've used before is to use a lock in your Elapsed event:
var myLock = new Object();
private void timerDoJob_Elapsed(object sender, ElapsedEventArgs e)
{
lock (myLock) {
VeryLongTask1();
VeryLongTask2();
VeryLongTask3();
}
}
This way, two instances of the Elapsed event cannot run at the same time. However, there is a caveat: If the task takes longer than two or more iterations of the timer, then you can have iterations adding up in the background. For example, if your timer elapses after 5 seconds, but your task takes 60 seconds to complete, by the time the first one finishes, you'll have 11 waiting.
Timer.Change method giving Timeout.Infinite and 0 as arguments will stop the timer (from MSDN):
If dueTime is zero (0), the callback method is invoked immediately. If
dueTime is Timeout.Infinite, the callback method is never invoked; the
timer is disabled, but can be re-enabled by calling Change and
specifying a positive value for dueTime.
One possible and simple but yet powerful approach is stopping the timer until the whole tasks have ended, and then, start the timer again:
private void timerDoJob_Elapsed(object sender, ElapsedEventArgs e)
{
timerDoJob.Change(Timeout.Infinite, 0);
// Use a try-finally so if some tasks throws an exception
// the timer will be re-enabled again anyway
try
{
VeryLongTask1();
VeryLongTask2();
VeryLongTask3();
}
finally
{
timerDoJob.Change(0, 5000);
}
}

Backgroundprocess for timebased operations

i have an application (.Net Framework 2.0!) where you can enter operations which will be executed at a given time.
Now i want to create a process which runs in background and does nothing else then waiting till the given time is reached and call the operation to run. The application should run things like making backup of specific parts of the computer, start updates, run batches, ... The backgroundworker will run over several month doing nothing else.
Using the code below would work but it seems a bit ugly. Is there any better solution?
while(true && !applicationClosing)
{
List<ExecProcess> processList = LoadStoredProcesses();
List<ExecProcess> spawnedProcesses = new List<ExecProcess>();
DateTime actualTime = DateTime.Now();
foreach(ExecProcess ep in processList)
{
if(ep.ExecutionTime < actualTime)
{
ep.Execute();
spawnedProcesses.Add(ep);
}
}
RemoveSpawnedProcesses(spawnedProcesses);
Thread.Sleep(1000);
}
Thank you verry much.
I would suggest using a Windows service which implements a timer that fires an event every n seconds. You can pickup your tasks from wherever you want, and queue them internally in the service and fire at given times. Just check the timestamps within the _executeTimer_Elapsed method. This is only a small sample, but it should be enough to get you started.
public class MyService : ServiceBase
{
private Timer _executeTimer;
private bool _isRunning;
public MyService()
{
_executeTimer = new Timer();
_executeTimer.Interval = 1000 * 60; // 1 minute
_executeTimer.Elapsed += _executeTimer_Elapsed;
_executeTimer.Start();
}
private void _executeTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!_isRunning) return; // logic already running, skip out.
try
{
_isRunning = true; // set timer event running.
// perform some logic.
}
catch (Exception ex)
{
// perform some error handling. You should be aware of which
// exceptions you can handle and which you can't handle.
// Blanket handling Exception is not recommended.
throw;
}
finally
{
_isRunning = false; // set timer event finished.
}
}
protected override void OnStart(string[] args)
{
// perform some startup initialization here.
_executeTimer.Start();
}
protected override void OnStop()
{
// perform shutdown logic here.
_executeTimer.Stop();
}
}

Check if timer elapsed in thread

I have a while loop running in my .NET backgroundworker. I would like to end the loop when Timers.Timer reaches 0.
Problem is that since I'm working in another thread (backgroundworker), my timer has to be instantiated in that same thread. So I can't set any private boolean timer_Elapsed. Nether do I know how to give reference of boolean thro event.
Code Example:
private bool timer_Elapsed = false;
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
System.Timers.Timer timer = new System.Timers.Timer();
Set_Timer(timer);
timer.Start();
while(timer_Elapsed) //Has to be a boolean that indicates if timer elapsed
{
this.Do_Proces();
}
}
private void Set_Timer(System.Timers.Timer timer)
{
timer.Interval = 200;
timer.Elapsed += new ElapsedEventHandler(timer_ElapsedEvent);
}
private void timer_ElapsedEvent(object source, ElapsedEventArgs e)
{
timer_Elapsed = true; //I can't set my private boolean since it got instantiated in another thread
}
Particular questions in code. I'm new with this kind of stuff.
Any suggestions? Thanks in advance
EDIT: To clarify, I want the Do_Proces() to run for 200 milliseconds, when that time passed, I want it to stop. When it stops after 200 millisec, I want to and update GUI with data generated in backgroundWorker. Then check if user wants the proces to stop, if not, I want it to run again.. I use the timer because the thread will have to get restarted to much, this will have effect on the main thread as well, effecting the user experience badly.
Is the timer serving any other purpose other than listed here? If not, you may just want to record the current time at the beginning of your BackgroundWorker method, and change the condition on the while loop to check if the required amount of time has elapsed.
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
TimeSpan timeout = TimeSpan.FromMinutes(5);
DateTime start_time = DateTime.Now;
while(DateTime.Now - start_time < timeout)
{
this.Do_Proces();
}
}

Alternative to Thread.Suspend() method

Thread.Suspend() method is obsolete as you know. I want to suspend thread immidiately when button click event comes. I used Thread.Suspend() and it works perfect but everyone suggest that using Thread.Suspend() method is not a good method to suspend the task. I used a flag to suspend the task but every time when a button click event comes, i have to wait to exit from task. I used Thread.IsAlive flag to wait the thread to exit but this method freezes form.
void ButtonClickEvent(object sender, ButtonClickEventArgs e)
{
TheadExitFlag = false;
if(MyThread != null)
{
while(MyThread.IsAlive);
//MyThread.Suspend();
}
}
void MyTask(void)
{
while(TheadExitFlag)
{
// some process
Thread.Sleep(5000);
}
}
How can i suspend the thread immidiately?
There is no alternative with the same functionality, AFAIK. I am not sure if the problems with an OS Suspend() could be worked around within the language/libraries, but no attempt has been made to do so, so maybe it's too difficult or even sensibly impossible.
Until such an alernative exists, you are reduced to polling for a suspend flag and then waiting on some synchronization object for a 'resume' signal. I have used AutoResetEvent for this.
Use a ManualResetEvent to toggle between a running and idle state.
ManualResetEvent run = new ManualResetEvent(true);
void ResumeButton_Click(object sender, ButtonClickEventArgs e)
{
run.Set();
PauseButton.Enabled = true;
ResumeButton.Enabled = false;
}
void PauseButton_Click(object sender, ButtonClickEventArgs e)
{
run.Reset();
PauseButton.Enabled = false;
ResumeButton.Enabled = true;
}
void MyTask(void)
{
while (run.WaitOne()) // Wait for the run signal.
{
// Do work here.
}
}
There is an approximate solution to this problem at https://stackoverflow.com/a/45786529/3013473 using AspectJ and wait/notify.

Categories