I have simple Console application in C# that creates a timer to write text to the Console. Then it waits for the user to press a key.
If the user presses a key before five seconds elapse, then the application ends, and the timer never fires. If the user does not press a key, then the timer fires as expected.
Why does the thread that the timer creates not keep the application from terminating? How should I ensure that the application keeps running even if the user presses a key?
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer(5000);
timer.Interval = 5000; // 5 seconds
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Enabled = true;
timer.AutoReset = true;
timer.Start();
Console.ReadKey();
}
public static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("Timer Fired.");
}
To get the timer message to always write out, you can have the main thread wait on a reset event that is signaled once the timer is fired.
static ManualResetEvent timerFired = new ManualResetEvent(false);
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer(5000);
timer.Interval = 5000; // 5 seconds
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Enabled = true;
timer.AutoReset = true;
timer.Start();
Console.ReadKey();
// This call will return only after timerFired.Set() is
// called. So, if the user hits a key before the timer is
// fired, this will block for a little bit, until the timer fires.
// Otherwise, it will return immediately
timerFired.WaitOne();
}
public static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("Timer Fired.");
timerFired.Set();
}
As for the other question, why doesn't it prevent the application from exiting, I'll take a stab. The timer_Elapsed() is being called from a background thread. According to MSDN, background threads don't keep the execution environment running. There's a nice discussion here.
ThreadPool threads are background threads, and MSDN Timer documentation indicates that the Timer's Elapsed event is raised on a ThreadPool thread, so the application wouldn't wait for it as it's not a foreground thread.
Related
I have an application that calls static methods in a DLL every 60 seconds as part of a system "self-check" application. When I manually run the methods, they all complete in less than 10 seconds. My problem is the timer.elapsed event is firing twice, one right after the other. To add to that, for each time the timer elapses, the event fires one more time. (e.g. first time it's 2 firings, second it's 3, third it's 4, etc.) I have tried setting the timer.AutoReset = false along with setting timer.Enabled = false at the beginning of the elapsed event and then setting it to true at the end of the event. I've tried resetting the interval in the event. Every post I have found indicates that the above actions should have resolved this problem. Can anyone help me find what I'm missing?
static Timer cycle = new Timer();
static int cycCount = 0;
static void Main(string[] args)
{
Console.WriteLine("Firebird Survivor Auto Cycle Started.");
Console.CancelKeyPress += Console_CancelKeyPress;
cycle.Interval = 60000; //set interval for service checks.
cycle.Elapsed += new ElapsedEventHandler(CycleComplete_Elapsed);
cycle.AutoReset = false;
cycle.Enabled = true;
cycle.Elapsed += CycleComplete_Elapsed;
while (1 == 1) //stop main method from completing indefinitely
{
//WAIT FOR TIMER TO ELAPSE
}
}
private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
cycle = null;
}
static void CycleComplete_Elapsed(object sender, ElapsedEventArgs e) //method triggered by timer
{
cycle.Enabled = false;
cycCount++;
WormholeServiceControls.CheckWormHoleStatus();
TimeControls.CheckTimePl(); //call time check
PegasusServiceControls.CheckPegasusStatus(null);
Console.Clear();
Console.WriteLine("--------------------------");
Console.WriteLine(String.Format("| Successful Cycles: {0} |", cycCount));
Console.WriteLine("--------------------------");
cycle.Enabled = true;
}
It seems your problem comes from the event handling you are doing. You are assigning the Elapsed event more than one time:
cycle.Elapsed += new ElapsedEventHandler(CycleComplete_Elapsed);
cycle.Elapsed += CycleComplete_Elapsed;
Why this two lines?. You will be all right with only this:
cycle.Elapsed += new ElapsedEventHandler(CycleComplete_Elapsed);
I'm trying to figure out how to make it so, after lets say, 1 minute so 60000 milliseconds the console will say hi.
All I have so far is
System.Timers.Timer timer = new System.Timers.Timer(60000);
timer.Start();
But I don't know how to make it so when the timer is done, it will do something.
You can use the elapse event, when 60000 ms has pass the event will be thrown. Example of the elapse event:
class Program
{
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer(60000);
timer.Elapsed += new System.Timers.ElapsedEventHandler(elapse); // subscribing to the elapse event
timer.Start(); // start Timer
Console.ReadLine(); // hold compiler until key pressed
}
private static void elapse(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Hy");
}
}
or
void Main()
{
var t = new System.Threading.Timer((s)=>Console.WriteLine("Hi"),null,0,60000);
Console.ReadLine();
}
You can use System.Threading.Thread.Sleep if you only want to do the write once (the timer will run every x seconds):
System.Threading.Thread.Sleep(60000);
Console.WriteLine("something");
What you will want to do is create an event that writes to the console when the timer has elapsed the predefined amount of time.
This is done as follows:
Start by creating your timer and set it to 60s:
var timer = new System.Timers.Timer(60000); //60seconds
Next create an event that will be triggered when the time has elapsed:
private static void MyEvent(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Hello World");
}
Next, bind the timer to that event:
timer.Elapsed += MyEvent;
What this does is tell the computer that when the timer actually starts running in the future and then the timer elapses (60s passes after the timer starts), then the Event called 'MyEvent' will be called which writes to the console.
Finally Start the timer:
timer.Start();
And wait for the even to trigger and write to the console.
In my application I'm using two Timer, each Timer use a BackgroundWorker. Here the declaration:
DispatcherTimer timer1 = new DispatcherTimer();
DispatcherTimer timer2 = new DispatcherTimer();
BackgroundWorker worker1 = new BackgroundWorker();
BackgroundWorker worker2= new BackgroundWorker();
I using timer1 for perform an heavy method with a BackgroundWorker and timer2 for execute another BackgroundWorker that check the content of a file.
In this way I assign the event to BackgroundWorkers:
worker1.DoWork += worker_DoWork;
worker1.RunWorkerCompleted += worker_RunWorkerCompleted;
worker1.WorkerSupportsCancellation = true;
worker2.DoWork += worker_DoWork2;
worker2.RunWorkerCompleted += worker_RunWorkerCompleted2;
worker2.WorkerSupportsCancellation = true;
Now timer1 have a range of 15 minutes so the BackgroundWorker execute the heavy method each 15 minutes. And timer2 have a range of 1 second. With the timer1 all working good, but the problems are coming when I've added the timer2.
As I said before this timer allow me to start a method that read a file through the worker2, this file have a property, if this property change I need to perform some special activity. Until here no problem.
What I did is the following:
//This method is called by MainWindow
public ReadFile()
{
//before this I already assigned to timer1 the tick event and start
timer2.Tick -= new EventHandler(Event_Tick);
timer2.Tick += new EventHandler(Event_Tick);
timer2.Interval = new TimeSpan(0, 0, 1);
timer2.Start();
}
This is the Tick event associated to timer2
private void Event_Tick(object sender, EventArgs e)
{
if (!worker1.IsBusy) //I skip the reading, worker1 is busy
{
timer1.Stop(); //stop the first timer
worker2.RunWorkerAsync();
}
else
{
Console.WriteLine("worker1 is busy!");
}
}
I don't need to add here the DoWork, is just a parsing of a file, very useless for the question. When worker2 complete the task I did this:
private void worker_RunWorkerCompleted2(object sender, RunWorkerCompletedEventArgs e)
{
timer1.Start();
ReadFile();
}
How you can see I start the timer1 again, and execute again the ReadFile method. Now if timer1 has reached the interval, so 15 minutes has passed, should execute the timer1.Tick += new EventHandler(Heavy_Tick); that execute the DoWork to worker1. But the timer1 never start.
I can't figure out to this, what am I doing wrong?
Now I get it!
You want to execute worker1 every 15 minutes and worker2 every second but only when worker1 is not busy. Your problem is this here:
if (!worker1.IsBusy) //I skip the reading, worker1 is busy
{
timer1.Stop(); //stop the first timer
worker2.RunWorkerAsync();
}
and this:
public ReadFile()
{
//before this I already assigned to timer1 the tick event and start
timer2.Tick -= new EventHandler(Event_Tick);
timer2.Tick += new EventHandler(Event_Tick);
timer2.Interval = new TimeSpan(0, 0, 1);
timer2.Start();
}
Set both timer intervals and tick event handlers during startup, e.g. Form_Load()or at the beginning of Main(). Start them there too. You should not have to stop any timer at all!
By setting the interval, all you have to do is handle the Tick() event. Remove your .Start() and Stop() calls from your WorkerCompletedand Tick methods and you should do fine.
So a lot could be going on here but you should make sure that:
You timer isn't storing it's old progress and you are checking for a certain length of time before stopping. This will automatically cause the timer to stop when restarting.
The timer.stop() function is not disposing your object to an un-restart-able state.
You aren't accessing the timer variable through some pointer that is maintain a stopped value. (Unlikely but annoying when it happens)
I'd personally consider just pausing the timer and resetting the progress, instead of fully stopping it since this is causing issues.
How can I restrict timer thread execution time? I have long running timer work that should work no more than 30 seconds.
The only way to do this is to have a second thread (possibly the one that created the worker thread) monitor and then kill it or gracefully call it to quit immediately. Killing threads you should avoid, and only use as the last resort. Here is example how:
Thread t = new Thread(myLongThreadProc);
t.Start();
Thread.Sleep(30000);
t.Abort();
By 'gracefully call it to quit', I mean to set some stop variable to some value, and give the thread some short time to quit itself, otherwise you kill it. But it is the design of your thread function to make it actually quit. Here is the sample code:
Thread t = new Thread(myLongThreadProc);
threadRun = true;
t.Start();
Thread.Sleep(30000);
threadRun = false; //this variable is monitored by thread
if (!t.Join(1000)) //inside your thread, make sure it does quit in one second
{ //when this variable is set to false
t.Abort();
}
And should I mention that your caller thread does not have to sleep for 30 seconds, but you can use a timer instead (if it is a form thread) or do something useful and check periodically - or have a third worker thread just counting 30 seconds...
Just have your worker method start a 30-second timer and check to see if it's elapsed as your worker does its thing:
bool timerElapsed;
public void DoWork()
{
timerElapsed=false;
System.Timers.Timer timer = new System.Timers.Timer(30000);
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
while (true)
{
if (timerElapsed)
{
// handle 30-sec elasped error
break;
}
// continue doing work and break when done
}
timer.Stop();
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timerElapsed = true;
}
I have a windows service written in C# that executes a method correctly. I added a timer to schedule the method execution and it doesn't seem to fire the ElapsedEventHandler event.
System.Timers.Timer timer = new System.Timers.Timer();
public LabelService()
{
InitializeComponent();
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
}
public void SetTimer()
{
DateTime nextRunTime = GetNextRunTime();
var ts = nextRunTime - DateTime.Now;
timer.Interval = ts.TotalMilliseconds;
timer.AutoReset = false;
timer.Start();
}
void timer_Elapsed(object source, ElapsedEventArgs e)
{
// ** never gets here **
timer.Stop();
// run some code
SetTimer();
}
I can run and hit a breakpoint at timer.Start(); so I know that's being done, but it never falls into the timer_Elapsed method. (For testing I change ts.TotalMilliseconds to 1000) Any ideas?
"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. When Enabled is true and AutoReset is true, the Timer continues to raise the Elapsed event on the specified interval."
So I think you gotta set
timer.AutoReset = true;
I know this is old, but for anyone else with the same problem I was able to work around this by using;
public void StartTimer()
{
_timer.Interval = _pollingIntervalMilliseconds;
_timer.Enabled = true;
_timer.AutoReset = false; // We must manually restart the timer when we have finished processing
_timer.Elapsed += CheckForUpdates;
_timer.Start();
if (Environment.UserInteractive)
{
Console.WriteLine("System now running, press a key to Stop");
Console.ReadKey();
}
}
private void CheckForUpdates(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Checking For Update");
DoSomethingSlow();
_timer.Start(); // restarts the timer to hit this method again after the next interval
}
It will keep hitting the Elapsed Event until you hit a key to exit
From comments on the question you say you are calling it like this:
#if (!DEBUG)
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new LabelLoader() };
ServiceBase.Run(ServicesToRun);
#else
LabelLoader ll = new LabelLoader();
ll.Start();
#endif
If you are in debug mode that means your main method is this:
LabelLoader ll = new LabelLoader();
ll.Start();
This means that once it has run these two lines the program finishes running and presumably exits. It doesn't matter what your timer is up to, the program has quit and thus your timer never fires.
I'd advise testing your ll with a better harness. Personally I use a winform type interface and just have a start button to mimic the service start (which will then have your code in the button click). Once I think I have that code running as I want I then test it in a service environment.