System.Timers.Timer Elapsed event executing after timer.Stop() is called - c#

Background: I have a timer that I am using to keep track of how long it has been since the serialPort DataReceived event has been fired. I am creating my own solution to this instead of using the built in timeout event because I am getting a continuous stream of data, instead of sending a query and getting one response.
The Problem:
In the DataReceived handler I have a statement to stop the timer so that is doesn't elapse. the problem is that a lot of the time it still executes the Elapsed handler afterword.
I have read that is is possible to use SynchronizingObject to solve this problem but I am not sure how to accomplish that.
Here is my code: I tried to cut out everything that I didn't think was relevant.
private System.Timers.Timer timeOut;
private System.Timers.Timer updateTimer;
public void start()
{
thread1 = new Thread(() => record());
thread1.Start();
}
public void requestStop()
{
this.stop = true;
this.WaitEventTest.Set();
}
private void record()
{
timeOut = new System.Timers.Timer(500); //** .5 Sec
updateTimer = new System.Timers.Timer(500); //** .5 Sec
timeOut.Elapsed += TimeOut_Elapsed;
updateTimer.Elapsed += updateTimer_Elapsed;
updateTimer.AutoReset = true;
comport.Open();
comport.DiscardInBuffer();
comport.Write(COMMAND_CONTINUOUSMODE + "\r");
stopwatch.Reset();
stopwatch.Start();
recordingStartTrigger(); //** Fire Recording Started Event
timeOut.Start();
updateTimer.Start();
this.waitHandleTest.WaitOne(); //** wait for test to end
timeOut.Stop();
updateTimer.Stop();
comport.Write(COMMAND_COMMANDMODE + Environment.NewLine);
comport.DiscardInBuffer();
comport.Close();
recordingStopTrigger(status); //** Fire Recording Stopped Event
stopwatch.Stop();
}
//***********************************************************************************
//** Events Handlers
private void comDataReceived_Handler(object sender, SerialDataReceivedEventArgs e)
{
double force = -100000;
string temp = "-100000";
//timeOut.SynchronizingObject.Invoke(new Action(()=> {timeOut.Stop();}), new object[] {sender, e});
timeOut.Stop();
//** I removed my action code here, keep things simple.
timeOut.Start();
}
private void TimeOut_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timeOut.Stop();
updateTimer.Stop();
//** fire delegate that GUI will be listening to, to update graph.
if (eventComTimeOut != null && this.stop == false)
{
if (eventComTimeOut(this, new eventArgsComTimeOut(comport.PortName, "READ")))
{
//retry = true;
comport.Write(COMMAND_CONTINUOUSMODE + "\r");
updateTimer.Start();
timeOut.Start();
}
else
{
this.stop = true;
//retry = false;
this.WaitEventTest.Set();
status = eventArgsStopped.Status.failed;
}
}
}
void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//** fire delegate that GUI will be listening to, to update graph.
List<Reading> temp = new List<Reading>(report.Readings_Force);
eventNewData(this, new eventArgsNewData(temp));
}

This is well known behavior. System.Timers.Timer internally uses ThreadPool for execution. Runtime will queue the Timer in threadpool. It would have already queued before you have called Stop method. It will fire at the elapsed time.
To avoid this happening set Timer.AutoReset to false and start the timer back in the elapsed handler if you need one. Setting AutoReset false makes timer to fire only once, so in order to get timer fired on interval manually start timer again.
yourTimer.AutoReset = false;
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
// add your logic here
}
finally
{
yourTimer.Enabled = true;// or yourTimer.Start();
}
}

I did a pause in timer with this code. for me that works.
Private cTimer As New System.Timers.Timer
Private Sub inittimer()
cTimer.AutoReset = True
cTimer.Interval = 1000
AddHandler cTimer.Elapsed, AddressOf cTimerTick
cTimer.Enabled = True
End Sub
Private Sub cTimerTick()
If cTimer.AutoReset = True Then
'do your code if not paused by autoreset false
End If
End Sub

Had the same problem and after some trying ended up with timer object to null and replace the timer variable it with a new timer object fixed the issue. I know its heavy of resources. But it solves the problem.

Related

More timers at same time in different threads

bool elapsed = false;
private void timerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
elapsed = true;
}
private void WorkerThreadFunction()
{
Timer _timer = new System.Timers.Timer(60000);
_timer.Elapsed += timerElapsed;
_timer.AutoReset = false;
while (!elapsed)
{
// Do something...
Thread.Sleep(50);
}
}
How is the global variable "elapsed" reacting? Is it possible to run more separate WorkerThreads with timers?
Of course it is possible to run more separate WorkerThreads. Each one will have it's own timer. There shouldn't be a problem.
The variable bool elapsed will be set to true by the first Thread that finishes its job, and it will stay true until some other process sets it to false. If you are unlucky some thread might even not start its job because the first on has set your elapsed to true
EDIT:
it seems that your thread job is encapsulated.
So you could actually also just use a stopwatch, if you don't need to access global variables from within the thread
private void WorkerThreadFunction()
{
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
while(watch.ElapsedMilliseconds < 60000)
{
// Do something...
Thread.Sleep(50);
}
watch.Stop();
}

Timer does not fire in a multi-thread form

I have a System.Timers.Timer timer in a form. Also I have a thread that reads from an RFID device (with function: GetData()). I want to limit the time of my thread with a timer, but the timer does not fire.
System.Threading.Thread GetData;
System.Timers.Timer timer = new System.Timers.Timer();
int reverseCounter=1000;
public CardDragMaifareFrm()
{
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Interval = 10;
timer.Enabled = true;
timer.Start();
GetData = new Thread(new ThreadStart(ReadCardData));
GetData.Start();
}
void timer_Elapsed(object sender, EventArgs e)
{
if (reverseCounter > 0)
{
MessageBox.Show("hey");
reverseCounter -= 1;
}
else
{// some actions for terminating GetData thread}
}
but I don't see "hey" message... can anybody help me? thanx
I used the first rule of computer engineering: Restart it, maybe it will work"... ;-)

Remove or Replace Invoke Delegate C#

Before all. I'm not so good at this and hopefully you will understand it anyway.
Im making a function in my program where it checks to see if a row in a rtb is highlighted. If not, it highlights it.
For this to work I had to use different threads to be able to access the rtb from different places. My problem is that it creates a new "delegate"/instance/thread every time the timer refreshes. I would like to remove the old thread/delegate or replace it with the new.
Because now the program crashes after a while. It's a very small program but after 40 sec i reach over 3gb ram usage.
Thanks in advance!
Haris.
Code:
private void Timer()//Timer for color refresh
{
aTimer = new System.Timers.Timer(300);
aTimer.Elapsed += new ElapsedEventHandler(Form1_Load);
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private void RefreshColor()//Refreshing the color of selected row
{
this.Invoke((MethodInvoker)delegate
{
if (richTextBox1.SelectionBackColor != Color.PaleTurquoise)
{
HighlightCurrentLine();
}
});
}
private void Form1_Load(object sender, EventArgs e)
{
Timer();
RefreshColor();
What is happening if i am not mistaken is that you are creating and starting new timers exponentially. So your forms loads, Form1_Load method is called. Form1_Load creates a new timer that when elapsed, will call Form1_Load again. As the old timer not being disposed 2 timers are running now that will both create 2 new timers. 4 timers create 4 new so there are 8, 16, 32 and so on...
Basically what you have to do is call other method on timer elapsed:
private void Timer()//Timer for color refresh
{
aTimer = new System.Timers.Timer(300);
aTimer.Elapsed += ATimer_Elapsed;//new ElapsedEventHandler(Form1_Load);
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private void ATimer_Elapsed(object sender, ElapsedEventArgs e)
{
RefreshColor();
}
private void RefreshColor()//Refreshing the color of selected row
{
this.Invoke((MethodInvoker)delegate
{
if (richTextBox1.SelectionBackColor != Color.PaleTurquoise)
{
HighlightCurrentLine();
}
});
}
private void Form1_Load(object sender, EventArgs e)
{
Timer();
RefreshColor();
Timer(); is only called ones thus creating only one timer.

System.Timers.Timer() Firing multiple times due to aggregation of Elapsed Events

I want to have a section of my code start a timer once it's called, and I want this timer to keep running until I quit the whole program. My problem is, each time I call OnSomethingHappens() , the Elapsed events aggregate (despite my effort with -= ) and the timer starts firing one extra time (or at least this is what I think is happening). I have also tried defining the timer within the class, to no avail. Here's the related part of my code:
public override void OnSomethingHappens()
{
Timer aTimer= new System.Timers.Timer();
aTimer.Elapsed -= (sender, e) => DoSomethingElse(sender, e);
aTimer.Stop();
aTimer.Close();
aTimer.Elapsed += (sender, e) => DoSomethingElse(sender, e);
aTimer.Interval = 1000;
aTimer.AutoReset = true; // I want the timer to keep working, but only fire once each time
Console.WriteLine("Enabling Timer aTimer");
aTimer.Start();
}
I cannot use static (not sure how that would help but I saw timers being defined as static in many sources) because this class has many instances, and I want them to have separate timers.
Thank you.
Start your timer without the AutoReset and restart it at the end of the DoSomethingElse.
aTimer.AutoReset = false;
aTimer.Start();
DoSomethingElse(..)
{
// do stuff here
aTimer.Start();
}
if each instance of this class uses his own timer , so static is no needed.
private Timer _aTimer;
public void OnSomethingHappens()
{
if (_aTimer != null)
{
_aTimer.Enabled = true; // start timer
return;
}
_aTimer = new System.Timers.Timer();
_aTimer.Elapsed += DoSomethingElse;
_aTimer.Interval = 1000; // every 1 second
_aTimer.Enabled = true; // start timer
}
private void DoSomethingElse(object sender, ElapsedEventArgs e)
{
_aTimer.Enabled = false; // stop timer
// do w/e you want
}
First thing you should really only create once instance of the timer, and hook up one event listener. With your current code, a new timer is being created, with an event listener, every time the method is called. Instead make the timer a class variable, and hook up the event listener in the constructor.
You can start the timer in the OnSomethingHappens, but what do you want to happen on subsequent calls to the method? Should the timer restart, or just continue?
You would probably also want to make the class IDisposable, or at least provide a Stop method to stop the timer when the application closes.
public class MyClass : MyBaseClass, IDisposable
{
private Timer _timer;
private volatile bool _isStopped = true;
public MyClass()
{
_timer = new Timer();
_timer.Interval = 1000;
_timer.Elapsed = OnTimerElapsed;
}
public void Stop()
{
_isStopped = true;
_timer.Stop();
}
public void Dispose()
{
if (_timer != null)
{
Stop();
_timer = null;
}
}
protected override void OnSomethingHappens()
{
if (_timer.Enabled)
{
// Restart or do nothing if timer is already running?
}
else
{
_isStopped = false;
_timer.Start();
}
}
private void OnTimerElapsed(object sender, EventArgs a)
{
if (_isStopped)
{
// If the Stop method was called after the Elapsed event was raised, don't start a long running operation
return;
}
}
}

Timer tick events does not fire in a backgroundworker do_work

I have a background worker which i am using to perform some task. Its working as expected. However, i have a timer that i want to add and make it start the bw and counting like 10 seconds after page load. I put my timer.Interval to 10000. the timer has a tick events as below
private DateTime dateETA;
private void TimerEventHandler(object sender, EventArgs e)
{
while (bw.CancellationPending ==false)
{
if (timerPro.Enabled == true)
{
dateETA = Convert.ToDateTime("1/1/0001 00:00:00");
dateETA = dateETA.AddMilliseconds(timerPro.Interval);
lblETA.Visible = true;
lblETA.Text = "Elapsed Time : " + Convert.ToString(dateETA.TimeOfDay);
// SetText("timer");
}
}
}
My background worker async is on the page contructor method and therefore run on load. just like below
if (bw.IsBusy != true)
{
this.btnPause.Enabled = true;
this.btnStop.Enabled = true;
btnStart.Enabled = false;
// timerPro.Start();
bw.RunWorkerAsync();
}
I wanted to start the timer together with my task therefore i put it before my bw.async . Then i realized the timer tick events does not fire when put before or within the dowork method of the background worker. I thought may be the bw thread is blocking the event from firing then i use an invoke method like below within the dowork in my attempt to start the timer or trigger the tick event of the timer.
this.Invoke((MethodInvoker)(() => { timerPro.Enabled = true; }));
It still does not fire. I am confused and any help or alternative would be appreciated.
I think you just want a running elapsed timer while the backgroundworker does its thing?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private System.Diagnostics.Stopwatch SW = new System.Diagnostics.Stopwatch();
private void Form1_Load(object sender, EventArgs e)
{
timerPro.Interval = 1000;
timerPro.Tick +=new EventHandler(TimerEventHandler);
SW.Start();
timerPro.Start();
bw.RunWorkerAsync();
}
private void TimerEventHandler(object sender, EventArgs e)
{
lblETA.Visible = true;
TimeSpan TS = SW.Elapsed;
string elapsed = String.Format("{0}:{1}:{2}", TS.Hours.ToString("00"), TS.Minutes.ToString("00"), TS.Seconds.ToString("00"));
lblETA.Text = "Elapsed Time : " + elapsed;
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
// ... do some work ...
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
timerPro.Stop();
}
}

Categories