Failure to stop ticking with Windows Form Timer in C# - 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.

Related

Disabling and enabling a timer causes a second instance?

I have a Start and Stop button on a form that start and stop a repeating SQL query which sends data to a pubnub channel. When I fire up the form and click start, I see what I expect on the subscribed clients. However, if I click stop then start again, I now get duplicate data. A third time gives me triplicate data, etc. What is causing this? Here are the start and stop methods:
private void btnQuery1Start_Click(object sender, EventArgs e)
{
lblQuery1Status.Text = "Status: Running";
btnQuery1Start.Enabled = false;
txtQuery1Interval.Enabled = false;
btnQuery1Stop.Enabled = true;
query1Timer.Elapsed += new ElapsedEventHandler(doQuery1);
query1Timer.Interval = Convert.ToInt32(txtQuery1Interval.Text) * 1000;
query1Timer.Enabled = true;
}
private void btnQuery1Stop_Click(object sender, EventArgs e)
{
btnQuery1Start.Enabled = true;
btnQuery1Stop.Enabled = false;
txtQuery1Interval.Enabled = true;
query1Timer.Enabled = false;
lblQuery1Status.Text = "Status: Stopped";
}
I can post doQuery1 if necessary, but it's using an OdbcConnection and data reader to get a single integer result then it's serializing it with Newtonsoft.Json and sending it using Pubnub.publish(). I'm hoping though that this is something obvious I'm just missing in the btnQuery1Start_Click() method above.
No, you have a single timer - but you're adding an event handler to it every time you click start:
query1Timer.Elapsed += new ElapsedEventHandler(doQuery1);
Just move that line into wherever you construct the timer, so it only gets added once, and it'll be fine.
(I'd personally rewrite it as query1Timer.Elapsed += doQuery1;, but that's your call...)
Every time you press start you add the event handler to the timer, but on stop you don't remove it.
Every time you click start you are executing the line:
query1Timer.Elapsed += new ElapsedEventHandler(doQuery1);
This adds a new event handler each time it is called causing your doQuery1 method to be executed multiple times

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

Prevent the console from closing while debugging

My problem is that the console should stay opened. The timer cannot write anything into the console while Console.ReadLine() waits for an input. How do I prevent the console from closing without using Console.ReadLine(), Console.ReadKey() or system("pause")?
Here is my code:
namespace Closer {
public static class Program {
public static void Main () {
// Define timer
var t = new Windows.Forms.Timer() {
Enabled = true,
Interval = 30000
};
// Give timer the tick function
t.Tick += (object tSender, EventArgs tE) => {
// If it is half past eleven
if (DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() == "2330") {
// Close all osu!.exe's --- works
foreach (Process p in Process.GetProcessesByName("osu!")) {
p.Kill();
}
// Write a msg
Console.WriteLine("Done!");
}
};
// Prevent the console from closing --- Here's the problem
Console.ReadLine();
}
}
}
You are conflating two problems. Yes, an early release of .NET 4.5 made the mistake of having Console.ReadLine() take a lock that prevented threads from writing to the console. That was fixed, just turn on Windows Update to get the service release.
But the real problem is your Timer class selection. A System.Windows.Forms.Timer requires a message loop to get the Tick event to fire. You can only get a message loop by calling Application.Run(). A very suitable replacement for Console.ReadLine() btw, use Application.ExitThread() to get your app to terminate.
You should use System.Threading.Timer or System.Timers.Timer in a console mode app. Their callback is fired on a threadpool thread so don't require a dispatcher loop.
You should use System.Timers.Timer and everything works fine.
static void Main()
{
// Define timer
System.Timers.Timer t = new System.Timers.Timer()
{
Enabled = true,
Interval = 1000
};
// Give timer the tick function
t.Elapsed += (object tSender, System.Timers.ElapsedEventArgs tE) =>
{
Console.WriteLine("Done!");
};
Console.ReadLine();
}
You can try this:
Thread.CurrentThread.Join();
I know this is stupid, but this does what you need. And the process will never terminate (itself) you've to kill manually.

Timer Skipping ElapsedEvents

So I'm trying to run an event every 5 seconds. Seems to work using System.Timers.Timer to some extend but it seems to be skipping sometimes, not even responding late, just plain skipping it.
Anything I could do about this?
internal void DetermineScreenCapping()
{
System.Timers.Timer ScreenCapTimer = new System.Timers.Timer();
/// Initialize the screencapper (doesn't enable it yet)
// Tell the timer what top do when it elapses
ScreenCapTimer.Elapsed += new ElapsedEventHandler(ExecuteCode);
// Set it to go off every five seconds
ScreenCapTimer.Interval = 5000;
// And start it
ScreenCapTimer.Enabled = true;
}
private void ExecuteCode(object source, ElapsedEventArgs e)
{
if (IsCurrentlyWorking == true)
{
Execute Code
}
}
The problem indeed wasn't the timer not doing it's job. It was the code being executed that had some problems that couldn't even be seen debugging for some reason.
I changed the code and the timer works properly now ^^

C# - how do you stop a timer?

I know it sounds stupid, but I've tried everything to stop a timer, but the timer won't stop. I'm working on a game and i would appreciate if someone could tell me how to stop a timer.
If you are using System.Timers.Timer stopping is performed by one of the options:
//options 1
timer.Enabled = false
//option 2
timer.Stop()
if you are using System.Threading.Timer, use this method
timer.Change(Timeout.Infinite , Timeout.Infinite)
if you are using System.Windows.Forms.Timer, use this method
timer.Stop();
So to add to the previous answers, in case you are using the System.Threading.Timer class,
this will stop it permanently with no further chance to use the same instance:
timer.Dispose()
otherwise:
timer.Change(Timeout.Infinite, Timeout.Infinite)
System.Windows.Forms.Timer: timer.Enabled = false;
System.Threading.Timer: timer.Change(Timeout.Infinite, Timeout.Infinite);
System.Timers.Timer: timer.Enabled = false; or timer.Stop();
With each of the timers in the .NET framework, it's possible that the timer fires just before you stop it, so you'll see the callback after you stop it.
You'll need to use something like an asynchronous callback context: use a bool set to true when you want the timer running, and set it to false when you stop it. Then have your callback check your context to see if it should really run or not.
Assuming you are making use of the System.Windows.Forms.Timer; since there was no explicit reference to anything else...if that is the case...
System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
myTimer.Stop();
Depends on the timer. If it is from threading namespace, dispose of it and recreate it when you need to, or have your timer delegate wait on reset event(see msdn). System.Timers namespace has a start and stop method.
I also ran into the similar problem many times.
//Timer init.
var _timer = new System.Timers.Timer
{
AutoReset = true,
Enabled = true,
Interval = TimeSpan.FromSeconds(15).TotalMilliseconds //15 seconds interval
};
_timer.Elapsed += DoSomethingOnTimerElapsed;
//To be called on timer elapsed.
private void DoSomethingOnTimerElapsed(object source, ElapsedEventArgs e)
{
//Disable timer.
_timer.Enabled = false; //or _timer.Stop()
try
{
//does long running process
}
catch (Exception ex)
{
}
finally
{
if (_shouldEnableTimer) //set its default value to true.
_timer.Enabled = true; //or _timer.Start()
}
}
//somewhere in the code if you want to stop timer:
_timer.Enabled = _shouldEnableTimer = false;
//At any point, if you want to resume timer add this:
_timer.Enabled = _shouldEnableTimer = true;
Why to do so?
Lets assume, the code inside the try block takes more time. So, by the time you disable timer (_timer.Enabled = false or _timer.Stop()), there is high possibilty that the code inside try block is still executing. Hence, after completion of the task when it comes to finally, it is again enabled if there is no flag(_shouldEnableTimer) check. Therefore, I prevent your problem by adding an additional flag check.
For more clarity, please go through the code and the added comments. Hope this helps.

Categories

Resources