How to reduce the processor consumption? - c#

I have made a C# alarm clock and it's working fine. the problem is that when it runs it consumes 20% of the processor (on an i5 2410M processor) what should I do?
here is my code:
using System;
namespace assigment1
{
class Program
{
static void Main(string[] args)
{
DateTime uptime = new DateTime (2013,12,10,4,0,0);
Console.WriteLine("This alarm is set to go off at 4:00 am");
while (true)
{
if (DateTime.Now.Minute == uptime.Minute && DateTime.Now.Hour == uptime.Hour)
{
for (int j = 1000; j < 22767; j++)
{
Console.Beep(j, 500);
Console.Write("Wake up! it is {0}:{1} already! ", DateTime.Now.Hour, DateTime.Now.Minute);
}
}
}
}
}
}

This is because your while loop is running continuously without any break. Add a Thread.Sleep. This will add a pause in between checks and greatly increase your performance:
class Program
{
static void Main(string[] args)
{
DateTime uptime = new DateTime (2013,12,10,4,0,0);
Console.WriteLine("This alarm is set to go off at 4:00 am");
while (true)
{
if (DateTime.Now.Minute == uptime.Minute && DateTime.Now.Hour == uptime.Hour)
{
for (int j = 1000; j < 22767; j++)
{
Console.Beep(j, 500);
Console.Write("Wake up! it is {0}:{1} already! ", DateTime.Now.Hour, DateTime.Now.Minute);
}
}
Thread.Sleep(1500); // Sleep 1.5 seconds.
}
}
}

You need to calculate the time till till the alarm should beep and use the timer class. Just set the interval to the time remaining till alarm and stop the timer after that. Something like this should work
DateTime alarmTime = new DateTime(2013,12,10,4,0,0);
System.Windows.Forms.Timer alarmTimer = new System.Windows.Forms.Timer();
alarmTimer.Interval = (alarmTime - DateTime.Now).Milliseconds;
alarmTimer.Tick += alarmTimer_Tick;
alarmTimer.Start();
your event
void alarmTimer_Tick(object sender, EventArgs e)
{
alarmTimer.Stop();
Console.Write("Wake up! it is {0}:{1} already! ", DateTime.Now.Hour, DateTime.Now.Minute);
}

if you want an alarm clock why you don't use Timer Class

I don't know if you can do that, but you can change the thread priority of the executing thread via the Priority property. You may want to try the following:
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
Also, I don't think you really want to cap it. If the machine is otherwise idle, you'd like it to get busy on with the task, right? ThreadPriority helps communicate this to the scheduler.

You are putting the check within a while loop, which means it will be utilising a large proportion of your processor time.
I would suggest having a look at this article (http://www.infolet.org/2012/11/create-digital-clock-on-c-sharp-program-code.html) which describes how to do this using the Timer Class.
UPDATE:
This SO answer is pretty nice and may be more suited if you're happy to use events;
https://stackoverflow.com/a/1493235/465404

I think you should definitely be using a Timer class for your alarm and just change the tick interval accordingly. This will easily allow you to manage recurrence of the alarm as well.
So you're interval will be the difference in time between when the alarm is set and when you want it to go off.
I have used multiple of these running concurrently in a Win Forms app with very small resource utilisation.

Related

Automatic battery level check in C#

I'm working on a speech recognition program in C# and I've compiled a few lines of code that speaks back the current battery level when I say "battery level".
if (e.Result.Text.ToLower() == "battery level")
{
System.Management.ManagementClass wmi = new System.Management.ManagementClass("Win32_Battery");
var allBatteries = wmi.GetInstances();
//String estimatedChargeRemaining = String.Empty;
int batteryLevel = 0;
foreach (var battery in allBatteries)
{
batteryLevel = Convert.ToInt32(battery["EstimatedChargeRemaining"]);
}
if(batteryLevel < 25)
JARVIS.Speak("Warning, Battery level has dropped below 25%");
else //Guessing you want else
JARVIS.Speak("The battery level is at: " + batteryLevel.ToString() + "%");
return;
}
Instead of this line happening only when I say "battery level" I want it to automatically check the battery level every 15mins and automatically report back to me via speech if the battery level has dropped bellow 25%:
if(batteryLevel < 25)
JARVIS.Speak("Warning, Battery level has dropped below 25%");
I am guessing I will require a timer but other than that I have no idea.
Thanks.
One option is System.Threading.Timer. The pertinent pieces are the callback and the interval.
There is more information from that page though that dictate whether that is the right choice for you. Some highlights are:
System.Threading.Timer is a simple, lightweight timer that uses callback methods and is served by thread pool threads. It is not recommended for use with Windows Forms, because its callbacks do not occur on the user interface thread. System.Windows.Forms.Timer is a better choice for use with Windows Forms. For server-based timer functionality, you might consider using System.Timers.Timer, which raises events and has additional features.
and
As long as you are using a Timer, you must keep a reference to it. As with any managed object, a Timer is subject to garbage collection when there are no references to it. The fact that a Timer is still active does not prevent it from being collected.
Edit: Now that you've stated you're in WinForms you can see that MSDN recommends the System.Windows.Forms.Timer. That MSDN page gives an example. You'll see that subscribing to the Tick event is your callback and Interval is the time between ticks in milliseconds. You want to set it to the 15 minutes you stated which is going to be 1000 * 60 * 15 or 900000.
Adapted from the MSDN Example:
private static readonly Timer batteryCheckTimer = new Timer();
// This is the method to run when the timer is raised.
private static void CheckBattery(Object sender, EventArgs myEventArgs)
{
ManagementClass wmi = new ManagementClass("Win32_Battery");
var allBatteries = wmi.GetInstances();
foreach (var battery in allBatteries)
{
int batteryLevel = Convert.ToInt32(battery["EstimatedChargeRemaining"]);
if (batteryLevel < 25)
{
JARVIS.Speak("Warning, Battery level has dropped below 25%");
}
}
}
[STAThread]
public static void Main()
{
// Start the application.
Application.Run(new Form1());
batteryCheckTimer.Tick += new EventHandler(CheckBattery);
batteryCheckTimer.Interval = 900000;
batteryCheckTimer.Start();
}
Loop call in every 15 minutes will cause MainUI thread to response poor and the application will get crashed. You can solve this by using Threading. Please check out the below code snippet which will help your needs. You can use SystemInformation class by referring System.Windows.Forms namespace instead of WMI query. Set Timer control interval by 900000 to execute the action every 15 minutes. Please mark the answer if useful
public delegate void DoAsync();
public void Main()
{
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 900000;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
DoAsync async = new DoAsync(GetBatteryDetails);
async.BeginInvoke(null, null);
}
public void GetBatteryDetails()
{
int i = 0;
PowerStatus ps = SystemInformation.PowerStatus;
if (ps.BatteryLifePercent <= 25)
{
if (this.InvokeRequired)
this.Invoke(new Action(() => JARVIS.Speak("Warning, Battery level has dropped below 25%");
else
JARVIS.Speak("Warning, Battery level has dropped below 25%");
}
i++;
}
As McAden said, timers can be used. An example of a timer can be found on the msdn website.

How to create an event that fires at certain time [duplicate]

I have a service written in C# (.NET 1.1) and want it to perform some cleanup actions at midnight every night. I have to keep all code contained within the service, so what's the easiest way to accomplish this? Use of Thread.Sleep() and checking for the time rolling over?
I wouldn't use Thread.Sleep(). Either use a scheduled task (as others have mentioned), or set up a timer inside your service, which fires periodically (every 10 minutes for example) and check if the date changed since the last run:
private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);
protected override void OnStart(string[] args)
{
_timer = new Timer(10 * 60 * 1000); // every 10 minutes
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Start();
//...
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// ignore the time, just compare the date
if (_lastRun.Date < DateTime.Now.Date)
{
// stop the timer while we are running the cleanup task
_timer.Stop();
//
// do cleanup stuff
//
_lastRun = DateTime.Now;
_timer.Start();
}
}
Check out Quartz.NET. You can use it within a Windows service. It allows you to run a job based on a configured schedule, and it even supports a simple "cron job" syntax. I've had a lot of success with it.
Here's a quick example of its usage:
// Instantiate the Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();
// Instantiate the JobDetail object passing in the type of your
// custom job class. Your class merely needs to implement a simple
// interface with a single method called "Execute".
var job = new JobDetail("job1", "group1", typeof(MyJobClass));
// Instantiate a trigger using the basic cron syntax.
// This tells it to run at 1AM every Monday - Friday.
var trigger = new CronTrigger(
"trigger1", "group1", "job1", "group1", "0 0 1 ? * MON-FRI");
// Add the job to the scheduler
scheduler.AddJob(job, true);
scheduler.ScheduleJob(trigger);
A daily task? Sounds like it should just be a scheduled task (control panel) - no need for a service here.
Does it have to be an actual service? Can you just use the built in scheduled tasks in the windows control panel.
The way I accomplish this is with a timer.
Run a server timer, have it check the Hour/Minute every 60 seconds.
If it's the right Hour/Minute, then run your process.
I actually have this abstracted out into a base class I call OnceADayRunner.
Let me clean up the code a bit and I'll post it here.
private void OnceADayRunnerTimer_Elapsed(object sender, ElapsedEventArgs e)
{
using (NDC.Push(GetType().Name))
{
try
{
log.DebugFormat("Checking if it's time to process at: {0}", e.SignalTime);
log.DebugFormat("IsTestMode: {0}", IsTestMode);
if ((e.SignalTime.Minute == MinuteToCheck && e.SignalTime.Hour == HourToCheck) || IsTestMode)
{
log.InfoFormat("Processing at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
OnceADayTimer.Enabled = false;
OnceADayMethod();
OnceADayTimer.Enabled = true;
IsTestMode = false;
}
else
{
log.DebugFormat("Not correct time at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
}
}
catch (Exception ex)
{
OnceADayTimer.Enabled = true;
log.Error(ex.ToString());
}
OnceADayTimer.Start();
}
}
The beef of the method is in the e.SignalTime.Minute/Hour check.
There are hooks in there for testing, etc. but this is what your elapsed timer could look like to make it all work.
As others already wrote, a timer is the best option in the scenario you described.
Depending on your exact requirements, checking the current time every minute may not be necessary.
If you do not need to perform the action exactly at midnight, but just within one hour after midnight, you can go for Martin's approach of only checking if the date has changed.
If the reason you want to perform your action at midnight is that you expect a low workload on your computer, better take care: The same assumption is often made by others, and suddenly you have 100 cleanup actions kicking off between 0:00 and 0:01 a.m.
In that case you should consider starting your cleanup at a different time. I usually do those things not at clock hour, but at half hours (1.30 a.m. being my personal preference)
I would suggest that you use a timer, but set it to check every 45 seconds, not minute. Otherwise you can run into situations where with heavy load, the check for a particular minute is missed, because between the time the timer triggers and the time your code runs and checks the current time, you might have missed the target minute.
You can also try the TaskSchedulerLibrary here http://visualstudiogallery.msdn.microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8
Implement the abstract class AbstractScheduledTask and call the ScheduleUtilityFactory.AddScheduleTaskToBatch static method
For those that found the above solutions not working, it's because you may have a this inside your class, which implies an extension method which, as the error message says, only makes sense on a non-generic static class. Your class isn't static. This doesn't seem to be something that makes sense as an extension method, since it's acting on the instance in question, so remove the this.
Try this:
public partial class Service : ServiceBase
{
private Timer timer;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
SetTimer();
}
private void SetTimer()
{
if (timer == null)
{
timer = new Timer();
timer.AutoReset = true;
timer.Interval = 60000 * Convert.ToDouble(ConfigurationManager.AppSettings["IntervalMinutes"]);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
}
private void timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
//Do some thing logic here
}
protected override void OnStop()
{
// disposed all service objects
}
}

How to close a console application within the specified number of hours?

I was tasked to append a timer within my working console app to let it close automatically after some time without requiring a user input.
My application has functions that delete certain data in the database based on some conditions and exits everytime the user inputs 'exit'.
Now the requirement is to automatically stop the process even if the deleting of items is not yet done given that the time set to close the application is provided, say 2 hours.
Can someone help me?
Thanks.
You can create a System.Timers.Timer with an interval of TimeSpan.FromHours(2) and call Environment.Exit() in its Elapsed handler.
I don't believe that killing the program is a good idea since you are manipulating data in a database but I think would be the simplest way to do it.
using Timer = System.Threading.Timer;
class Program
{
private static readonly Timer _timer =
new Timer(o => Environment.Exit(0), null, 5000, Timeout.Infinite);
static void Main(string[] args)
{
Console.ReadLine();
}
}
1) create a timer
2) set interval and the elapsed event handler
3) enable the timer for run
when timer triggers in the method hooked to the event just exit the application
If you are deleting data from database then stopping it Abruptly could be catastrophic. So you can implement somthing like this.
Perform the time consuming operation in a BackGroundWorker
Implement a Timer as explained in other examples.
Then when the Tick/Interval Event is raised Request the BackgroundWorker to Cancel the Task.
In your Do Work code Listen for this Cancel request and stop the deletion process safely(Either the Do Deletion or Don't Perform the it At all)
Then Use Environment.Exit() to exit out of the program.
Hope it helps
I solved this problem by having an app.config file where there is a value for key="Stoptime".
I then added a condition that checks the current time against the set end time. Following is an example solution (for those having the same problem):
public static void Main(string[] args)
{
string stoptime = ConfigurationManager.AppSettings["Stoptime"];
DateTime timeEnd = Convert.ToDateTime(stoptime);
today = DateTime.Now;
Console.WriteLine(today);
for (int i = 0; i < 100000; i++)
{
id.Add(i.ToString());
}
foreach(string item in id)
{
today = DateTime.Now;
if (timeEnd.CompareTo(today) >= 0)
{
Console.CursorLeft = 0;
Console.Write(item + " " + today);
}
else
{
Console.WriteLine();
Console.WriteLine("break.");
break;
}
}
Console.ReadKey();
}

.NET, event every minute (on the minute). Is a timer the best option?

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));
}
}

How can I raise an event every hour (or specific time interval each hour) in .NET?

I'm working on a little web crawler that will run in the system tray and crawl a web site every hour on the hour.
What is the best way to get .NET to raise an event every hour or some other interval to perform some task. For example I want to run an event every 20 minutes based on the time. The event would be raised at:
00:20
00:40
01:00
01:20
01:40
and so on. The best way I can think of to do this is by creating a loop on a thread, that constantly checks if the time is divisible by a given interval and raises a callback event if the time is reached. I feel like there has got to be a better way.
I'd use a Timer but I'd prefer something that follows a "schedule" that runs on the hour or something along those lines.
Without setting up my application in the windows task scheduler is this possible?
UPDATE:
I'm adding my algorithm for calculating the time interval for a timer. This method takes a "minute" parameter, which is what time the timer should trigger a tick. For example, if the "minute" parameter is 20, then the timer will tick at the intervals in the timetable above.
int CalculateTimerInterval(int minute)
{
if (minute <= 0)
minute = 60;
DateTime now = DateTime.Now;
DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
TimeSpan interval = future - now;
return (int)interval.TotalMilliseconds;
}
This code is used as follows:
static System.Windows.Forms.Timer t;
const int CHECK_INTERVAL = 20;
static void Main()
{
t = new System.Windows.Forms.Timer();
t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
t.Tick += new EventHandler(t_Tick);
t.Start();
}
static void t_Tick(object sender, EventArgs e)
{
t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
}
System.Timers.Timer. If you want to run at specific times of the day, you will need to figure out how long it is until the next time and set that as your interval.
This is just the basic idea. Depending on how precise you need to be you can do more.
int minutes = DateTime.Now.Minute;
int adjust = 10 - (minutes % 10);
timer.Interval = adjust * 60 * 1000;
You may find help from Quartz.net http://quartznet.sourceforge.net/
Here is an example of a lightweight system using thread timing and an asynch call.
I know there are some downsides, but I like using this instead of a timer when kicking off a long running process (like schedualed backend services). Since it runs inline in the timer thread, you don't have to worry about it getting kicked off again before the the original call has finished. This could be extended quite a bit to make it use an array of datetimes as the trigger times or add some more abilities to it. I am sure some of you guys out there know some better ways.
public Form1()
{
InitializeComponent();
//some fake data, obviously you would have your own.
DateTime someStart = DateTime.Now.AddMinutes(1);
TimeSpan someInterval = TimeSpan.FromMinutes(2);
//sample call
StartTimer(someStart,someInterval,doSomething);
}
//just a fake function to call
private bool doSomething()
{
DialogResult keepGoing = MessageBox.Show("Hey, I did something! Keep Going?","Something!",MessageBoxButtons.YesNo);
return (keepGoing == DialogResult.Yes);
}
//The following is the actual guts.. and can be transplanted to an actual class.
private delegate void voidFunc<P1,P2,P3>(P1 p1,P2 p2,P3 p3);
public void StartTimer(DateTime startTime, TimeSpan interval, Func<bool> action)
{
voidFunc<DateTime,TimeSpan,Func<bool>> Timer = TimedThread;
Timer.BeginInvoke(startTime,interval,action,null,null);
}
private void TimedThread(DateTime startTime, TimeSpan interval, Func<bool> action)
{
bool keepRunning = true;
DateTime NextExecute = startTime;
while(keepRunning)
{
if (DateTime.Now > NextExecute)
{
keepRunning = action.Invoke();
NextExecute = NextExecute.Add(interval);
}
//could parameterize resolution.
Thread.Sleep(1000);
}
}
Another strategy for this would be to record the LAST TIME that the process was run and determine if your desired interval has elapsed since that time. In this strategy, you would code your event to fire if the elapsed time is equal to OR GREATER THAN the desired interval. In this way you can handle instances where long intervals (once per day, for example) could be missed if the computer were to be down for some reason.
So for example:
lastRunDateTime = 5/2/2009 at 8pm
I want to run my process every 24 hours
On a timer event, check whether 24 hours OR MORE passed since the last time the process was run.
If yes, run the process, update lastRunDateTime by adding the desired interval to it (24 hours in this case, but whatever you need it to be)
Obviously, for this to recover after the system has gone down, you will need to store lastRunDateTime in a file or database somewhere so the program could pick up where it left off on recovery.
System.Windows.Forms.Timer (or System.Timers.Timer)
but since now you say you don't want to use Timers, you can run a lightweight wait process on another thread (check time, sleep a few seconds, check time again...) or make a component that raises an event (using a lightweight wait process) on certain scheduled times or intervals
The following should do the trick.
static void Main(string[] Args)
{
try
{
MainAsync().GetAwaiter().GetResult();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static async Task MainAsync()
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
// Start the timed event here
StartAsync(tokenSource.Token);
Console.ReadKey();
tokenSource.Cancel();
tokenSource.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
var nextRunTime = new DateTime();
switch (DateTime.Now.AddSeconds(1) < DateTime.Today.AddHours(12)) // add a second to current time to account for time needed to setup the task.
{
case true:
nextRunTime = DateTime.Today.AddHours(12); // Run at midday today.
break;
case false:
nextRunTime = DateTime.Today.AddDays(1).AddHours(12); // Run at midday tomorrow.
break;
}
var firstInterval = nextRunTime.Subtract(DateTime.Now);
Action action = () =>
{
// Run the task at the first interval, then run the task again at midday every day.
_timer = new Timer(
EventMethod,
null,
firstInterval,
DateTime.Today.AddDays(1).AddHours(12).Subtract(DateTime.Now)
);
};
// no need to await this call here because this task is scheduled to run later.
Task.Run(action);
return Task.CompletedTask;
}
private async void EventMethod(object state)
{
// do work
}
My goal is to run an import around 03:00 every night.
Here's my approach, using System.Timers.Timer:
private Timer _timer;
private Int32 _hours = 0;
private Int32 _runAt = 3;
protected override void OnStart(string[] args)
{
_hours = (24 - (DateTime.Now.Hour + 1)) + _runAt;
_timer = new Timer();
_timer.Interval = _hours * 60 * 60 * 1000;
_timer.Elapsed += new ElapsedEventHandler(Tick);
_timer.Start();
}
void Tick(object sender, ElapsedEventArgs e)
{
if (_hours != 24)
{
_hours = 24;
_timer.Interval = _hours * 60 * 60 * 1000;
}
RunImport();
}

Categories