I have a c# windows service with a timer that executes a process every 5 minutes.
I don't want to create other process to execute a task every 30 minutes, so is it possible within the same timer timer_Elapsed event to do that logic? any clue?
Thanks a lot,
How about using 2 timers?
You could increment a variable every time the timer elapses, and when that variable reaches 6, you reset it to 0 and execute your 'once every 30 minute' code. Also, creating a new (winform) timer does not create a new thread as far as I know.
int TimerVariable=0;
TimerEvent(object sender,eventargs e)
{
TimerVariable++;
if(TimverVariable>=6)
{
//Execute the once every 30 min code
}
//Execute the once every 5 min code.
}
Well, you could just use a counter and check it against 6(30000/5000) and reset it back to zero when done.
private int counter = 0;
private void TimerCallback()
{
counter++;
if(counter >=6)
{
//Your 30 seconds code here
counter = 0;
}
}
Related
How do I wait for a specified time while showing the remaining time to wait?
I now solved it like this but I feel like this is a really bad way to do it:
//This is running in a BackgroundWorker:
Stopwatch watch = new Stopwatch();
watch.Start();
while(watch.ElapsedMilliseconds != SecondsToWait * 1000)
{
TimeToNextRefresh = ((SecondsToWait * 1000) - watch.ElapsedMilliseconds) / 1000;
Thread.Sleep(1);
}
watch.Stop();
So here I am guessing that the condition (watch.ElapsedMilliseconds != SecondsToWait * 1000) is checked every millisecond.
So the main question is; In what period is the condition of while checked and/or how do I improve the code I've written?
It depends on what's the code inside while loop!
For example, if you write some really long/time-consuming code in a while loop, each iteration of the while loop, or course, will be longer than a while loop that only has short/fast code.
Compare these two while loops:
while (true) {
Console.WriteLine("Hello");
}
and
while (true) {
Console.Beep(5000);
}
Each iteration of the first while loop is faster than that of the second one because Console.Beep(5000) takes 5 seconds and Console.WriteLine only takes a fraction of a second.
So you can't rely on while loops to count time.
This is what you should do:
Create an instance of System.Windows.Forms.Timer, not the System.Timers.Timer nor the System.Threading.Timer. I find the first one the most useful (others are more advanced).
Timer timer = new Timer();
timer.Interval = 1000; // 1000 means 1000ms aka 1 second
timer.Tick += TimerTicked;
timer.Start();
Now the compiler will tell you that TimerTicked is not defined, so let's go define that:
private void TimerTicked(object sender, EventArgs e) {
}
Now you're all set. The code in TimerTicked will be called every one second.
Let's say you want to measure a time of 10 seconds. After 10 seconds, you want to do something. So first create a variable called secondsLeft in the class level:
int secondsLeft = 10;
Now in TimerTicked, you want to check whether secondsLeft is 0. If it is, do that something, else, minus one:
if (secondsLeft == 0) {
DoSomething();
} else {
secondsLeft--;
}
And secondsLeft is the time remaining! You can display it on a label or something.
To pause the timer, simply
timer.Stop();
The exact interval in which your while condition is checked is hard to predict. Thread.Sleep(1); only tells the operating system that you want your thread to sleep for at least 1 millisecond. There is no guarantee that your thread will be active again after exactly 1ms. Actually you can rather be sure that it will be more than that. The thread is scheduled again after 1ms, but there will be a delay until he gets his CPU time slot.
The interval you want for your loop actually depends how you want to display the remaining time. If you want to display only seconds, why would you update that display every millisecond, although the text would change only every 1000ms?
A loop like that is probably not a good way to implement something like that. I would recommend a System.Threading.Timer:
// this Timer will call TimerTick every 1000ms
Timer timer = new Timer(TimerTick, null, 0, 1000);
and implement the handler
public void TimerTick(object sender)
{
// update your display
}
Note that you will have the "update your display" part on the UI thread again, as this method is called by the Timer on a different thread.
This code is can really make an infinite loop if a calculation just take longer than 1 miliseconds.
You can achieve your desired behaviour with a simple System.Winforms.Forms.Timer like this snipped below :
private int tickCount = 0;
private int remaining = 10;
private void timer1_Tick(object sender, EventArgs e)
{
remaining--;
textBox1.Text = remaining.ToString();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 1000;
timer1.Enabled = true;
}
With this you can countdown from 10 seconds and every tick you write to a textbox the remaining seconds
I'm running into an issue where the Elapsed event is triggered prior to the interval. I have the interval set for say.. 10000ms and the event will get triggered at roughly 4500ms. I know that this specific timer is not too precise but I do know for sure that it is far more precise than what it is showing.
I have checked to make sure that there is not more than one timer calling this event as well. This solution works perfectly on two out of the three windows machines that it is installed on.
Could it be a problem with the .net version, clr version, etc.
I know that there are other ways of accomplishing this but I am just looking for suggestions on what could be causing this to work on only 2 out of 3 servers.
Below I am creating the timer only once at startup of the service..
checkTimer = new System.Timers.Timer(getSecondsLeft());
checkTimer.Elapsed += checkNowEvent;
checkTimer.AutoReset = true;
checkTimer.Enabled = true;
Here is the method that is used to calculate the number of milliseconds until the next minute
private double getSecondsLeft()
{
DateTime now = DateTime.Now;
// Has a chance to trigger a few milliseconds before new minute. Added 50ms to interval
return ((60 - now.Second) * 1000 - now.Millisecond) + 50;
}
And finally the elapsed time event.
private void checkNowEvent(object sender, ElapsedEventArgs e)
{
try
{
// Stop timer to keep from firing this event again
checkTimer.Enabled = false;
// DOING WORK HERE
}
finally
{
// Set the interval as to tick on the start of the next minute
checkTimer.Interval = getSecondsLeft();
// Start timer again
checkTimer.Enabled = true;
}
}
I just did some more testing with this and I added some stopwatch functionality to see if the interval was actually firing when it is supposed to and it looks like it is. However, when i calculate the correct number of milliseconds to the next minute BUT it is acting as if this implementation of Timer is running faster than the system clock... If that makes any sense.
Here is the code i used to find that out.
private void checkNowEvent(object sender, ElapsedEventArgs e)
{
stopWatch.Stop();
_Log.LogDebug(stopWatch.Elapsed.ToString());
try
{
// Stop timer to keep from firing this event again
checkTimer.Enabled = false;
// DOING WORK HERE
}
catch (Exception ex)
{
// CATCHING EXCEPTIONS HERE IF ANY
}
finally
{
// Set the interval as to tick on the start of the next minute
checkTimer.Interval = getSecondsLeft();
_Log.LogDebug(checkTimer.Interval.ToString());
// Start timer again
checkTimer.Enabled = true;
stopWatch.Reset();
stopWatch.Start();
}
}
The reason that it is firing before the new minute is due to the fact that there is a problem with the system time. DateTime.Now returns the correct number of milliseconds until the next minute but the system time is moving very slow. The timer implementation seems to be working correctly as I verified with the stopwatch. I just synced the system time with the other two working pcs and not but 5 minutes later it is a couple minutes slow again.
I have a timer running in my app which I want to stop and start according to local time.
So I need something like this:
if ( time = 08:00) {StartTimer();}
If ( time = 18:00) {StopTimer();} //This can be done from the timer event itself
Is there a way to do this without using another timer?
I can stop the timer from within the timer event itself, but how will i start it again?
You can set the timer's interval to 14 hours instead of stopping it or keep it running with short interval and checking additional condition (the time of the day) internally.
You can try this:-
1) Create a console app that does what you're looking for.
2) Use the Windows "Scheduled Tasks" functionality to have that console app executed at the time you need it to run
or
You can also look at this example:-
using System;
using System.Threading;
public class TimerExample {
// The method that is executed when the timer expires. Displays
// a message to the console.
private static void TimerHandler(object state) {
Console.WriteLine("{0} : {1}",
DateTime.Now.ToString("HH:mm:ss.ffff"), state);
}
public static void Main() {
// Create a new TimerCallback delegate instance that
// references the static TimerHandler method. TimerHandler
// will be called when the timer expires.
TimerCallback handler = new TimerCallback(TimerHandler);
// Create the state object that is passed to the TimerHandler
// method when it is triggered. In this case a message to display.
string state = "Timer expired.";
Console.WriteLine("{0} : Creating Timer.",
DateTime.Now.ToString("HH:mm:ss.ffff"));
// Create a Timer that fires first after 2 seconds and then every
// second.
using (Timer timer = new Timer(handler, state, 2000, 1000)) {
int period;
// Read the new timer interval from the console until the
// user enters 0 (zero). Invalid values use a default value
// of 0, which will stop the example.
do {
try {
period = Int32.Parse(Console.ReadLine());
} catch {
period = 0;
}
// Change the timer to fire using the new interval starting
// immediately.
if (period > 0) timer.Change(0, period);
} while (period > 0);
}
// Wait to continue.
Console.WriteLine("Main method complete. Press Enter.");
Console.ReadLine();
}
}
You could create a thread that ticks every second.
There you can check if you want to start or stop your timer.
Read the folowing: Threads.
In your thread add something like:
if (CurrentTime == "08:00")
StartTimer();
else if if (CurrentTime == "18:00")
StopTimer();
Thread.Sleep(1000); // Makes the Thread Sleep 1 Second
Since you need at least one timer running always (to detect when it's 8 in the morning) then you could simply have just a single timer that runs all day.
Whenever the timer ticks, check the time. If it isn't between 0800 and 1800 just return without doing anything and wait for the next tick.
You could try increasing the timer interval to a value that gets you to e.g. 17:55 and then decrease it again, but there will not be any measurable performance difference so IMHO this is work for no benefit.
What is the best way to simply wait for 24 hours +/- 1 second. I know that Threading.Sleep for a long time is not accurate and can vary based on the CPU loads.
I see the System.Timers.Timer allows you to create a timed event. How do I use this to simply wait for 24 hours?
private void myTest{
// SET SOMETHING UP
m_theTimer = new System.Timers.Timer();
m_theTimer.Elapsed += new ElapsedEventHandler(OurTimerCallback);
const int hrsToMs = 60 * 60 * 1000;
m_theTimer.Interval = TestPeriodHours * hrsToMs;
m_theTimer.Enabled = true;
//---->want to wait for 24 hours<------
// RESUME TEST HERE
VerifySomething()
}
public void OurTimerCallback(object source, ElapsedEventArgs e)
{
Console.WriteLine("Received a callback, the time is {0}", e.SignalTime);
}
Maybe Quartz.NET is what you are looking for. http://quartznet.sourceforge.net/.
+/- 1 second? I would use a hybrid approach.
Use task scheduler to start a program, in 23:58. Then have that program sleep for 2 minutes or less until the exact moment arrives, then perform the work.
If you don't care about the 1 second accuracy, you could just use task scheduler alone, on the 24 hour division.
Assuming you are on win forms.
Declare a datetime variable and assign a value on form_load event.
Create a timer and fire the the event in every second.
Check the datetime variable in the timer event. if timespan is 1 hour, call your main method.
I think you can use a combination of ManualResetEvent along with Timer.
Maybe this is better if you really want to use a timer.
private void myTest{
// SET SOMETHING UP
bool bTimer_Expired = true;
m_theTimer = new System.Timers.Timer();
m_theTimer.Elapsed += new ElapsedEventHandler(OurTimerCallback);
const int hrsToMs = 60 * 60 * 1000;
m_theTimer.Interval = TestPeriodHours * hrsToMs;
m_theTimer.Enabled = true;
//Wait for call back to set flag that the elapsed time has expired
while(!bTimer_Expired)Sleep(1000);
//---->want to wait for 24 hours<------
// RESUME TEST HERE
VerifySomething()
public void OurTimerCallback(object source, ElapsedEventArgs e)
{
bTimer_Expired=true;
Console.WriteLine("Received a callback, the time is {0}", e.SignalTime);
}
But I'm a little fuzzy on why ManuelResetEvent doesn't do the job easier....
I want to do stuff every minute on the minute (by the clock) in a windows forms app using c#. I'm just wondering whats the best way to go about it ?
I could use a timer and set its interval to 60000, but to get it to run on the minute, I would have to enable it on the minute precisely, not really viable.
I could use a timer and set its interval to 1000. Then within its tick event, I could check the clocks current minute against a variable that I set, if the minute has changed then run my code. This worries me because I am making my computer do a check every 1 second in order to carry out work every 1 minutes. Surely this is ugly ?
I'm using windows forms and .Net 2.0 so do not want to use the DispatchTimer that comes with .Net 3.5
This must be a fairly common problem. Have any of you a better way to do this?
Building on the answer from aquinas which can drift and which doesn't tick exactly on the minute just within one second of the minute:
static System.Timers.Timer t;
static void Main(string[] args)
{
t = new System.Timers.Timer();
t.AutoReset = false;
t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
t.Interval = GetInterval();
t.Start();
Console.ReadLine();
}
static double GetInterval()
{
DateTime now = DateTime.Now;
return ((60 - now.Second) * 1000 - now.Millisecond);
}
static void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine(DateTime.Now.ToString("o"));
t.Interval = GetInterval();
t.Start();
}
On my box this code ticks consistently within .02s of each minute:
2010-01-15T16:42:00.0040001-05:00
2010-01-15T16:43:00.0014318-05:00
2010-01-15T16:44:00.0128643-05:00
2010-01-15T16:45:00.0132961-05:00
How about:
int startin = 60 - DateTime.Now.Second;
var t = new System.Threading.Timer(o => Console.WriteLine("Hello"),
null, startin * 1000, 60000);
Creating a Timer control that fires every 1 second (and usually does nothing but a simple check) will add negligible overhead to your application.
Simply compare the value of Environment.TickCount or DateTime.Now to the last stored time (the previous 'minute tick'), and you should have a reasonably precise solution. The resolution of these two time values is about 15ms, which should be sufficient for your purposes.
Do note however that the interval of the Timer control is not guaranteed to be that precise or even anywhere now, since it runs on the Windows message loop, which is tied in with the responsiveness of the UI. Never rely on it for even moderately precise timing - though it is good enough for firing repeating events where you can check the time using a more sensitive method such as one of the two given above.
You can nail this with reactive extensions which will take care of lots of timer related problems for you (clock changes, app hibernation etc). Use Nuget package Rx-Main and code like this:
Action work = () => Console.WriteLine(DateTime.Now.ToLongTimeString());
Scheduler.Default.Schedule(
// start in so many seconds
TimeSpan.FromSeconds(60 - DateTime.Now.Second),
// then run every minute
() => Scheduler.Default.SchedulePeriodic(TimeSpan.FromMinutes(1), work));
Console.WriteLine("Press return.");
Console.ReadLine();
Read here (search for "Introducing ISchedulerPeriodic") to see all the issues this is taking care of: http://blogs.msdn.com/b/rxteam/archive/2012/06/20/reactive-extensions-v2-0-release-candidate-available-now.aspx
I jsut wrote this class using the WPF DispatcherTimer but you can swap the dispatcher for any timer that supports changing when it's woken from sleep state.
The class is constructed with a fixed time step and supprts Start/Stop/Reset, Start/Stop/Start works like a resume operation. The timer is like a stopwatch in that regard.
A clock implementation would simply create the class with a interval of 1 second and listen to the event. Be wary though that this is a real-time clock, if the tick event takes longer than the interval to finish you'll notice that the clock will try and catch up to real-time this will cause a burst of tick events being raised.
public class FixedStepDispatcherTimer
{
/// <summary>
/// Occurs when the timer interval has elapsed.
/// </summary>
public event EventHandler Tick;
DispatcherTimer timer;
public bool IsRunning { get { return timer.IsEnabled; } }
long step, nextTick, n;
public TimeSpan Elapsed { get { return new TimeSpan(n * step); } }
public FixedStepDispatcherTimer(TimeSpan interval)
{
if (interval < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException("interval");
}
this.timer = new DispatcherTimer();
this.timer.Tick += new EventHandler(OnTimerTick);
this.step = interval.Ticks;
}
TimeSpan GetTimerInterval()
{
var interval = nextTick - DateTime.Now.Ticks;
if (interval > 0)
{
return new TimeSpan(interval);
}
return TimeSpan.Zero; // yield
}
void OnTimerTick(object sender, EventArgs e)
{
if (DateTime.Now.Ticks >= nextTick)
{
n++;
if (Tick != null)
{
Tick(this, EventArgs.Empty);
}
nextTick += step;
}
var interval = GetTimerInterval();
Trace.WriteLine(interval);
timer.Interval = interval;
}
public void Reset()
{
n = 0;
nextTick = 0;
}
public void Start()
{
var now = DateTime.Now.Ticks;
nextTick = now + (step - (nextTick % step));
timer.Interval = GetTimerInterval();
timer.Start();
}
public void Stop()
{
timer.Stop();
nextTick = DateTime.Now.Ticks % step;
}
}
Create a method or put this code where you want the timer to start:
int time = 60 - DateTime.Now.Second; // Gets seconds to next minute
refreshTimer.Interval = time * 1000;
refreshTimer.Start();
And then on your tick event set the interval to 60000:
private void refreshTimer_Tick(object sender, EventArgs e)
{
refreshTimer.Interval = 60000; // Sets interval to 60 seconds
// Insert Refresh logic
}
By making use of ReactiveExtensions you could use the following code if you were interested in doing something as simple as printing to the console.
using System;
using System.Reactive.Linq;
namespace ConsoleApplicationExample
{
class Program
{
static void Main()
{
Observable.Interval(TimeSpan.FromMinutes(1))
.Subscribe(_ =>
{
Console.WriteLine(DateTime.Now.ToString());
});
Console.WriteLine(DateTime.Now.ToString());
Console.ReadLine();
}
}
}
Running a bit of code to see if the minute has changed once per second should not require much CPU time, and should be acceptable.
What about Quartz.NET? I think its a good framework to do timed actions.
You could set up two timers. An initial short interval timer (perhaps to fire every second, but dependent on how presice the second timer must fire on the minute).
You would fire the short interval timer only until the desired start time of the main interval timer is reached. Once the initial time is reached, the second main interval timer can be activated, and the short interval timer can be deactivated.
void StartTimer()
{
shortIntervalTimer.Interval = 1000;
mainIntervalTimer.Interval = 60000;
shortIntervalTimer.Tick +=
new System.EventHandler(this.shortIntervalTimer_Tick);
mainIntervalTimer.Tick +=
new System.EventHandler(mainIntervalTimer_Tick);
shortIntervalTimer.Start();
}
private void shortIntervalTimer_Tick(object sender, System.EventArgs e)
{
if (DateTime.Now.Second == 0)
{
mainIntervalTimer.Start();
shortIntervalTimer.Stop();
}
}
private void mainIntervalTimer_Tick(object sender, System.EventArgs e)
{
// do what you need here //
}
Alternatively, you could sleep to pause execution until it times out which should be close to your desired time. This will only wake the computer when the sleep finishes so it'll save you CPU time and let the CPU power down between processing events.
This has the advantage of modifying the timeout so that it will not drift.
int timeout = 0;
while (true) {
timeout = (60 - DateTime.Now.Seconds) * 1000 - DateTime.Now.Millisecond;
Thread.Sleep(timeout);
// do your stuff here
}
Use a timer set to run every second (or millisecond, whatever your accuracy threshold is), and then code the method to run your functionality if and only if the current time is within that threshold past the "on the minute" point.
What I'm using for scheduled tasks is a System.Threading.Timer(System.Threading.TimerCallback, object, int, int) with the callback set to the code I want to execute based on the interval which is supplied in milliseconds for the period value.
What about a combination of aquinas' answer and 'polling': (apologies for the mixture of languages)
def waitForNearlyAMinute:
secsNow = DateTime.Now.Second;
waitFor = 55 - secsNow;
setupTimer(waitFor, pollForMinuteEdge)
def pollForMinuteEdge:
if (DateTime.Now.Second == 0):
print "Hello, World!";
waitForNearlyAMinute();
else:
setupTimer(0.5, pollForMinuteEdge)
I have a solution based on Environment.TickCount
static void Main(string[] args)
{
//constatnt total miliseconds to one minute
const Int32 minuteMilisecond = 60 * 1000;
//get actual datetime
DateTime actualDateTime = DateTime.UtcNow;
//compenzation to one minute
Int32 nexTimer = Environment.TickCount + ((59 - actualDateTime.Second) * 1000) + (999 - actualDateTime.Millisecond);
//random fuction to simulate different delays on thread
Random rnd = new Random();
//main loop
while (true)
{
if (Environment.TickCount > nexTimer)
{
nexTimer += minuteMilisecond;
//execute your code here every minute
Console.WriteLine($"actual DateTime: {DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss:ffff")}");
}
//random sleep between 100 - 200 ms
Thread.Sleep(rnd.Next(100, 200));
}
}