System.Timers.Timer interval resetting causing restart - c#

I'm running into a problem with the System.Timers.Timer in a windows service. I basically set the timer up in a base polling service class with the following code:
_serviceTimer.Elapsed += OnElapsedTime;
_serviceTimer.Interval = ServiceTimerInterval.TotalMilliseconds;
_serviceTimer.AutoReset = false;
_serviceTimer.Enabled = true;
When the OnElapsedTime fires, I want to disable the timer and set the interval to a different value based on a lookup. The problem is when I change the interval it actually restarts the timer. This strange behavior is mentioned in the msndn docs with:
Note:
If Enabled and AutoReset are both set to false, and the timer has previously been enabled, setting the Interval property causes the Elapsed event to be raised once, as if the Enabled property had been set to true. To set the interval without raising the event, you can temporarily set the AutoReset property to true.
Timer.Interval
In the onelapsed event I have this:
_serviceTimer.Enabled = false;
double newIntervalSetting = newSetting;
base._serviceTimer.AutoReset = true;
base._serviceTimer.Interval = newIntervalSetting;
base._serviceTimer.AutoReset = false;
//reenable after processing
The problem is the interval change still begins the timer countdown and eventually fires off the event even though I set the autoreset to true prior to changing the interval. The enabled remains false at all times, but the event still fires. I'm not sure if I'm misinterpreting the msdn docs about the correct way to do this. Can anyone help me out?

I believe this has to do with the EventHandler being called from a different thread than the code currently setting Enabled to false.
According to MSDN Doc:
The signal to raise the Elapsed event
is always queued for execution on a
ThreadPool thread, so the
event-handling method might run on one
thread at the same time that a call to
the Stop method runs on another
thread. This might result in the
Elapsed event being raised after the
Stop method is called. The code
example in the next section shows one
way to work around this race
condition.
private static void HandleElapsed(object sender, ElapsedEventArgs e)
{
numEvents += 1;
// This example assumes that overlapping events can be
// discarded. That is, if an Elapsed event is raised before
// the previous event is finished processing, the second
// event is ignored.
//
// CompareExchange is used to take control of syncPoint,
// and to determine whether the attempt was successful.
// CompareExchange attempts to put 1 into syncPoint, but
// only if the current value of syncPoint is zero
// (specified by the third parameter). If another thread
// has set syncPoint to 1, or if the control thread has
// set syncPoint to -1, the current event is skipped.
// (Normally it would not be necessary to use a local
// variable for the return value. A local variable is
// used here to determine the reason the event was
// skipped.)
//
int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
if (sync == 0)
{
// No other event was executing.
// The event handler simulates an amount of work
// lasting between 50 and 200 milliseconds, so that
// some events will overlap.
int delay = timerIntervalBase
- timerIntervalDelta / 2 + rand.Next(timerIntervalDelta);
Thread.Sleep(delay);
numExecuted += 1;
// Release control of syncPoint.
syncPoint = 0;
}
else
{
if (sync == 1) { numSkipped += 1; } else { numLate += 1; }
}
}

Can you set a boolean m_SetEnabled = true in your existing OnElapsedTime event and then add if(m_SetEnabled) { m_SetEnabled = false; return; } to just ignore the single event that gets fired.

Related

Execute a function ever 60 seconds

I want to execute a function every 60 seconds in C#. I could use the Timer class like so:
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 60 * 1000; // in miliseconds
timer1.Start();
Question is I have a long running process. Occasionally it make take several minutes. Is there a way to make the timer smart so if the function is already being executed then it should skip that cycle and come back 60 seconds later and if again it is in execution then again skip and come back 60 seconds later.
I would suggest you to have a class member variable bool variable with value false.
then in click event return if its true at the beginning.
and then set it to true, so that it will tell you that its currently in execution.
then write your logic.
and then once done finally set it to false again.
code will look like this.
private bool isRunning = false;
private void timer1_Tick(object sender, EventArgs e)
{
if (isRunning)
{
return;
}
isRunning = true;
try
{
... //Do whatever you want
}
finally
{
isRunning = false;
}
}
The modern and most clean way to do this is using Microsoft's new Period Timer:
var timer = new PeriodicTimer(TimeSpan.FromSeconds(n));
while (await timer.WaitForNextTickAsync())
{
//Business logic
}
If you need to abort such a ticker, you can pass a cancellation token to the WaitForNextTickAsync method.
Another advantage is this:
The PeriodicTimer behaves like an auto-reset event, in that multiple ticks are coalesced into a single tick if they occur between calls to WaitForNextTickAsync(CancellationToken). Similarly, a call to Dispose() will void any tick not yet consumed. WaitForNextTickAsync(CancellationToken) may only be used by one consumer at a time, and may be used concurrently with a single call to Dispose().
Source: https://learn.microsoft.com/en-us/dotnet/api/system.threading.periodictimer.waitfornexttickasync?source=recommendations&view=net-7.0#remarks
If you need more granularity (like "always at 10 am", use something like https://github.com/HangfireIO/Cronos
Use a timer, set it to 60 second
On Event:
try
Stop timer
Do logic
catch
What ever fail recovery
finally
Start the timer
Logic is run 60 seconds after last finish.
You can use a Stopwatch inside a loop: start the stopwatch, after 60 second call the function, reset the stopwatch, start the loop again.

Windows Service recursive & infinite call

I have a Windows Service which connects to an external device (micro controller) to get data and save it to database. The external device does not support callback feature, that's why the service should ask for the data frequently.
What I did so far: I created a service with a timer which ticks frequently, based on configuration.
Here, I have two problems:
Sometimes the data very big, and before collecting and saving that data, the timer is restarting based on configuration. In this case, I'm losing the data.
If I configure the timer for longer period, I'm losing monitoring which data should be monitored immediately after collect.
I've read other related questions like doing a recursive call in the background service, etc. But I don't have exit condition for recursive call. Application should continue working even after some exception occurs.
Here is my code:
public partial class DataManagerService : ServiceBase
{
public DataManagerService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer = new System.Timers.Timer(1000);
timer.Elapsed += new System.Timers.ElapsedEventHandler(OnElapsedTime);
timer.Enabled = true;
}
private void OnElapsedTime(object source, System.Timers.ElapsedEventArgs e)
{
GetRecords();
}
protected override void OnStop()
{
// clean up
}
}
PS: I'm using .NET Framework 4.6.1 and Visual Studio 2017 Community edition
The System.Timers.Timer.Stop documentation contains a (non-trivial) example of how to accomplish this using two Timer instances. At each interval, a separate control Thread leverages:
a static currentTimer field to select the correct Timer instance
the System.Threading.Interlocked.CompareExchange static method to prevent overlapping Elapsed events.
Because I see a little ambiguity in your requirement, let me call out Microsoft's note about the use case for this approach versus System.Threading.Monitor:
If it were necessary to execute every event, the Monitor class would be a better way to synchronize the events.
From Microsoft docs System.Timers.Timer.Stop examples
The following code example shows one way to prevent the thread that calls the Stop method from continuing until a currently executing Elapsed event ends, and also to prevent two Elapsed events from executing the event handler at the same time (often referred to as reentrancy).
The example executes 100 test runs. Each time the test is run, the timer is started with an interval of 150 milliseconds. The event handler uses the Thread.Sleep method to simulate a task that randomly varies in length from 50 to 200 milliseconds. The test method also starts a control thread that waits for a second and then stops the timer. If an event is being handled when the control thread stops the timer, the control thread must wait until the event is finished before proceeding.
The Interlocked.CompareExchange(Int32, Int32, Int32) method overload is used to avoid reentrancy and to prevent the control thread from continuing until an executing event ends. The event handler uses the CompareExchange(Int32, Int32, Int32) method to set a control variable to 1, but only if the value is currently zero. This is an atomic operation. If the return value is zero, the control variable has been set to 1 and the event handler proceeds. If the return value is non-zero, the event is simply discarded to avoid reentrancy. (If it were necessary to execute every event, the Monitor class would be a better way to synchronize the events.) When the event handler ends, it sets the control variable back to zero. The example records the total number of events that executed, that were discarded because of reentrancy, and that occurred after the Stop method was called.
The control thread uses the CompareExchange(Int32, Int32, Int32) method to set the control variable to -1 (minus one), but only if the value is currently zero. If the atomic operation returns non-zero, an event is currently executing. The control thread waits and tries again. The example records the number of times the control thread had to wait for an event to finish.
using System;
using System.Timers;
using System.Threading;
public class Test
{
// Change these values to control the behavior of the program.
private static int testRuns = 100;
// Times are given in milliseconds:
private static int testRunsFor = 500;
private static int timerIntervalBase = 100;
private static int timerIntervalDelta = 20;
// Timers.
private static System.Timers.Timer Timer1 = new System.Timers.Timer();
private static System.Timers.Timer Timer2 = new System.Timers.Timer();
private static System.Timers.Timer currentTimer = null;
private static Random rand = new Random();
// This is the synchronization point that prevents events
// from running concurrently, and prevents the main thread
// from executing code after the Stop method until any
// event handlers are done executing.
private static int syncPoint = 0;
// Count the number of times the event handler is called,
// is executed, is skipped, or is called after Stop.
private static int numEvents = 0;
private static int numExecuted = 0;
private static int numSkipped = 0;
private static int numLate = 0;
// Count the number of times the thread that calls Stop
// has to wait for an Elapsed event to finish.
private static int numWaits = 0;
[MTAThread]
public static void Main()
{
Timer1.Elapsed += new ElapsedEventHandler(Timer1_ElapsedEventHandler);
Timer2.Elapsed += new ElapsedEventHandler(Timer2_ElapsedEventHandler);
Console.WriteLine();
for(int i = 1; i <= testRuns; i++)
{
TestRun();
Console.Write("\rTest {0}/{1} ", i, testRuns);
}
Console.WriteLine("{0} test runs completed.", testRuns);
Console.WriteLine("{0} events were raised.", numEvents);
Console.WriteLine("{0} events executed.", numExecuted);
Console.WriteLine("{0} events were skipped for concurrency.", numSkipped);
Console.WriteLine("{0} events were skipped because they were late.", numLate);
Console.WriteLine("Control thread waited {0} times for an event to complete.", numWaits);
}
public static void TestRun()
{
// Set syncPoint to zero before starting the test
// run.
syncPoint = 0;
// Test runs alternate between Timer1 and Timer2, to avoid
// race conditions between tests, or with very late events.
if (currentTimer == Timer1)
currentTimer = Timer2;
else
currentTimer = Timer1;
currentTimer.Interval = timerIntervalBase
- timerIntervalDelta + rand.Next(timerIntervalDelta * 2);
currentTimer.Enabled = true;
// Start the control thread that shuts off the timer.
Thread t = new Thread(ControlThreadProc);
t.Start();
// Wait until the control thread is done before proceeding.
// This keeps the test runs from overlapping.
t.Join();
}
private static void ControlThreadProc()
{
// Allow the timer to run for a period of time, and then
// stop it.
Thread.Sleep(testRunsFor);
currentTimer.Stop();
// The 'counted' flag ensures that if this thread has
// to wait for an event to finish, the wait only gets
// counted once.
bool counted = false;
// Ensure that if an event is currently executing,
// no further processing is done on this thread until
// the event handler is finished. This is accomplished
// by using CompareExchange to place -1 in syncPoint,
// but only if syncPoint is currently zero (specified
// by the third parameter of CompareExchange).
// CompareExchange returns the original value that was
// in syncPoint. If it was not zero, then there's an
// event handler running, and it is necessary to try
// again.
while (Interlocked.CompareExchange(ref syncPoint, -1, 0) != 0)
{
// Give up the rest of this thread's current time
// slice. This is a naive algorithm for yielding.
Thread.Sleep(1);
// Tally a wait, but don't count multiple calls to
// Thread.Sleep.
if (!counted)
{
numWaits += 1;
counted = true;
}
}
// Any processing done after this point does not conflict
// with timer events. This is the purpose of the call to
// CompareExchange. If the processing done here would not
// cause a problem when run concurrently with timer events,
// then there is no need for the extra synchronization.
}
// Event-handling methods for the Elapsed events of the two
// timers.
//
private static void Timer1_ElapsedEventHandler(object sender,
ElapsedEventArgs e)
{
HandleElapsed(sender, e);
}
private static void Timer2_ElapsedEventHandler(object sender,
ElapsedEventArgs e)
{
HandleElapsed(sender, e);
}
private static void HandleElapsed(object sender, ElapsedEventArgs e)
{
numEvents += 1;
// This example assumes that overlapping events can be
// discarded. That is, if an Elapsed event is raised before
// the previous event is finished processing, the second
// event is ignored.
//
// CompareExchange is used to take control of syncPoint,
// and to determine whether the attempt was successful.
// CompareExchange attempts to put 1 into syncPoint, but
// only if the current value of syncPoint is zero
// (specified by the third parameter). If another thread
// has set syncPoint to 1, or if the control thread has
// set syncPoint to -1, the current event is skipped.
// (Normally it would not be necessary to use a local
// variable for the return value. A local variable is
// used here to determine the reason the event was
// skipped.)
//
int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
if (sync == 0)
{
// No other event was executing.
// The event handler simulates an amount of work
// lasting between 50 and 200 milliseconds, so that
// some events will overlap.
int delay = timerIntervalBase
- timerIntervalDelta / 2 + rand.Next(timerIntervalDelta);
Thread.Sleep(delay);
numExecuted += 1;
// Release control of syncPoint.
syncPoint = 0;
}
else
{
if (sync == 1) { numSkipped += 1; } else { numLate += 1; }
}
}
}
/* On a dual-processor computer, this code example produces
results similar to the following:
Test 100/100 100 test runs completed.
436 events were raised.
352 events executed.
84 events were skipped for concurrency.
0 events were skipped because they were late.
Control thread waited 77 times for an event to complete.
*/

How do I stop a timer from activating if there is speech recognized?

I have a problem that I am having trouble resolving. Every two seconds a timer_elapsed event fires and moves to the next item in a group of choices. While this is happening, the application is waiting to hear a command using the Microsoft.Speech speech recognition libraries. When it hears that command it is supposed to move to the next group of choices. Sometimes though, the command comes exactly when the timer elapses and because the speech recognition is moving asynchronously the speechrecogonized event will move the choices to the next group while the timer will move within its group.
To control the movement through groups, I have created a set of modes. The timer will call a function based on the current mode. Speech controls what mode you're in and is changed within the speechrecognized event. I have tried putting the timer.stop() at the very beginning of the speechrecognized event but that is useless. They are called together at the same time quite often.
I am a beginning to average programmer. I understand the concepts behind threads but don't really have much experience working with them.
Thank you.
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(stopTimer)return;
if (mode == Mode.Group1)
{
displayGroup1();
}
else if (mode == Mode.Group2)
{
displayGroup2();
}
else if (mode == Mode.Group3)
{
displayGroup3();
}
}
void sre_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
{
stopTimer=false;
timer.Enabled = true;
}
void sre_SpeechDetected(object sender, SpeechDetectedEventArgs e)
{
stopTimer=true;
timer.Enabled = false;
}
private void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
timer.Stop();
stopTimer=true;
if (e.Result.Text == "yes")
{
changeMode();
}
}
I have pasted above the most relevant code sections and cleaned out unnecessary details.
Intro - what is it all about
In the following i will explain a basic solution which will attempt to implement a behavior (you might also call it a rule) for the case that Timer.Elapsed events overlap with incoming speech events.
The behaviour demonstrated here can be briefly explained as follows:
While an Timer.Elapsed event is executed, any incoming speech events should be ignored.
When a speech event occurs and no Timer.Elapsed events are executed, stop the timer and handle the speech event. After handling the speech event, restart the timer.
For the following explanation of the code, i assume the reader has an understanding of Microsoft Speech's SpeechRecognitionEngine class and its events.
The code and how it works
The SpeechDetected event handler stops the timer. It also checks, if the Timer.Elapsed event handler is currently executing (via isTimerElapsedHandlerExecuting) - if it does, the ignoreSpeechInput flag will be set to true, indicating that the processed audio data should be ignored.
(The lock i will explain in section 5.)
void sre_SpeechDetected(object sender, SpeechDetectedEventArgs e)
{
lock (_lockObj)
{
timer.Enabled = false;
//
// Given the the explanation above, i should write the code for
// setting of the ignoreSpeechInput flag like this:
// ignoreSpeechInput = isTimerElapsedHandlerExecuting ? true : false;
//
// But obviously that is the same as writing the following...
//
ignoreSpeechInput = isTimerElapsedHandlerExecuting;
}
}
The SpeechRecognized event handler decides based on the ignoreSpeechInput flag, whether the speech input should be ignored or not. It also restarts the timer (which was stopped in the SpeechDetected handler above.
private void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
if (!ignoreSpeechInput)
{
if (e.Result.Text == "yes")
changeMode();
}
timer.Enabled = true;
}
Similar to the SpeechRecognized handler, the handler for the SpeechRecognitionRejected event also needs to restart the timer.
void sre_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
{
timer.Enabled = true;
}
Beside its main functionality, the Timer.Elapsed event handler will also have to set isTimerElapsedHandlerExecuting accordingly to indicate whether it is executing or whether is finished (i.e., not executing).
You will also note that it explicitly test for Timer.Enabled. The reason for doing so is that there is a possibility that when Timer.Enabled is set back to false one or more Elapsed events are still queued for execution on a ThreadPool thread and which would be executed after Timer.Enabled has been set to false (although i don't really believe that this will happen with your timer interval of 2 seconds).
The try-finally simply ensures that isTimerElapsedHandlerExecuting will be set to false, even if the code in this method throws an exception.
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
lock (_lockObj)
{
if (!timer.Enabled)
return;
isTimerElapsedHandlerExecuting = true;
}
try
{
if (mode == Mode.Group1)
displayGroup1();
else if (mode == Mode.Group2)
displayGroup2();
else if (mode == Mode.Group3)
displayGroup3();
}
finally
{
isTimerElapsedHandlerExecuting = false;
}
}
Why is this lock(_lockObj) being used?
Without that lock your software could run into the following scenario:
sre_SpeechDetected is invoked, executing on thread A. More or less at the same time, timer_Elapsed is invoked, executing on thread B.
timer_Elapsed on thread B sees that Timer.Enabled is true.
A few ticks (CPU clock cycles) later, sre_SpeechDetected on thread A sets Timer.Enabled to false, and it also executes ignoreSpeechInput = isTimerElapsedHandlerExecuting;. isTimerElapsedHandlerExecuting is false at that point in time, thus ignoreSpeechInput becomes false, too.
Again a few ticks later, timer_Elapsed on thread B sets isTimerElapsedHandlerExecuting to true.
Now the speech event handlers incorrectly believe that no Timer.Elapsed handler is executing (because of ignoreSpeechInput == false).
The execution sequence illustrated in points 1. to 4. is called a "Race Condition", and is usually very difficult to debug, as the occurrence of such bugs often depend on a complex combination of certain characteristics of the CPU, overall system load,the behavior of OS and other software running on the system, the weather on that particular day, etc... Of course, this type of bug never occurs on the development and test systems, only on computers of customers ;-)
Summary of the variables used in the code and their default values (declared as private class members):
private readonly object _lockObj = new object();
private bool isTimerElapsedHandlerExecuting = false;
private bool ignoreSpeechInput = false;
private System.Timer timer = ...

Failure to stop ticking with Windows Form Timer in C#

I've initialized a windows form timer in my constructor (and set it running at an appropriate time by writing "pTimer.Enabled=true". In the constructor-
pTimer = new Timer();
pTimer.Enabled = false;
pTimer.Interval = timerSpeed;
pTimer.Tick += new EventHandler(pTimer_Tick);
Inside the timer callback, I'm checking to see if my work has been completed. Once it is, I'd like to stop the timer (in the sense that it won't keep calling the pTimer_Tick callback) and close a streamwriter that's doing the logging.
private void pTimer_Tick(object sender, EventArgs e)
{
bool tempFinished = finished();
log("finished() in timer tick = " + tempFinished.ToString());
if (tempFinished)
{
if (pTimer.Enabled == true)
{
log("We are going to stop the timer");
pTimer.Enabled = false;
Application.DoEvents();
log("We are going to close the streamwriter");
//myStreamWriter.Close();
}
}
}
The following behaviour seems to occur:
After the first time that finished()==true in the pTimer_Tick
callback, we log "finished() in timer tick = True", and the code
reaches pTimer.Enabled = false
Originally, I had not commented out closing the streamwriter and this was generating an error because it was continuing to attempt to write to code being logged from the pTimer_Tick callback
If we comment out myStreamWriter.Close(); (as written above), after 1. occurs, the code indeed seems to keep reentering the pTimer_Tick callback, it runs the finished() method when it reaches the "bool tempFinished=finished()" line, and the internal log to the finished() method indicates that it is going to output "true" again as expected, but the logging on the next line " log("finished() in timer tick = " + tempFinished.ToString());" is never down, and the next thing that appears in the log is the code accessing the finished() function again.
Does anyone have any suggestions about what could be wrong here?
Thanks!
Chris
You are starting and stopping the timer by setting the Enabled property. Although you claim in the comments that this is sufficient, I'm not convinced.
Try using the Start and Stop timer functions instead.

How do I add a delay after a count down timer

I am using a DispatcherTimer to perform a count down before triggering the release on a camera. The UpdateCountdown method is used to change the image displayed to the user before the camera fires. Rather than having the TakePicture method execute immediately, I would like have a slight delay after the counter reaches zero and the last image is displayed.
The code shown below results in the pause occurring at the _countdown = 1 point. While the final image displays and TakePicture() fires almost simultaneously (I think TakePicture happens first).
_countdownTimer = new DispatcherTimer();
_countdownTimer.Interval = TimeSpan.FromSeconds(1);
_countdownTimer.Tick += new EventHandler(delegate(object s, EventArgs a)
{ UpdateCountdown(); } );
_countdownTimer.Tick += new EventHandler(delegate(object s, EventArgs a)
{if (_countdown == _countdownMax)
{
System.Threading.Thread.Sleep(2000); // Slight delay before taking picture
Camera.TakePicture();
} });
}
public void StartCountdown()
{
if (doCount)
{
doCount = false;
UpdateCountdown();
_countdownTimer.Start();
}
}
private void UpdateCountdown()
{
_countdown--;
CountdownImage = _countDownImages[_countdown]; // Data bound to Image Control
if (_countdown == 0)
{
_countdown = _countdownMax;
_countdownTimer.Stop();
doCount = true;
}
What am I not taking into account with my timing?
The UI does not update immediately when you change control properties - it only updates when the thread becomes idle (that is, after all your event handlers finish executing).
Thread.Sleep blocks the thread, the event handlers don't finish executing and UI isn't redrawn.
You have to either use another timer (start a new timer on the last tick of the existing timer and call TakePicture on teh new timer's tick) or, even better, use the last tick of the existing timer - update UI when (_countdown <= _countdownMax), take picture when (_countdown == _countdownMax + 1).
Why not just make your display always show 1 less than the number of seconds remaining. That way when you get to zero, (obviously with a Math.Max(0, _countdown) to prevent showing -1) it will seem like the time has run out even though there's one more second to go.
Edit: What I meant to imply but did not state - was that you could then just have one Tick handler and not use Sleep at all which will just wind up blocking the UI anyway which will probably block your UI from updating.
I don't think that events guarantee that event handlers are triggered in the order that they are registered. Try
_countdownTimer.Tick += new EventHandler(delegate(object s, EventArgs a)
{
UpdateCountdown();
if (_countdown == _countdownMax)
{
System.Threading.Thread.Sleep(2000); // Slight delay before taking picture
Camera.TakePicture();
}
});
}

Categories

Resources