Thread sleep/wait until a new day
I'm running a process in a loop which has a limit on the number of operations it does per day. When it reaches this limit I've currently got it checking the the time in a loop to see if it a new date.
Would the best option be to:
- Keep checking the time every second for new date
- Calculate the number of seconds until midni开发者_开发知识库ght and sleep that length of time
- Something else?
Don't use Thread.Sleep for this type of thing. Use a Timer and calculate the duration you need to wait.
var now = DateTime.Now;
var tomorrow = now.AddDays(1);
var durationUntilMidnight = tomorrow.Date - now;
var t = new Timer(o=>{/* Do work*/}, null, TimeSpan.Zero, durationUntilMidnight);
Replace the /* Do Work */
delegate with the callback that will resume your work at the specified interval.
Edit: As mentioned in the comments, there are many things that can go wrong if you assume the "elapsed time" an application will wait for is going to match real-world time. For this reason, if timing is important to you, it is better to use smaller polling intervals to find out if the clock has reached the time you want your work to happen at.
Even better would be to use Windows Task Scheduler to run your task at the desired time. This will be much more reliable than trying to implement it yourself in code.
Windows has a task scheduler that handles exactly this duty. Create the program to do that which it is supposed to do. Then set it up as a scheduled task.
Just calculate a period to wait and run an asynchronous timer in this way you can avoid extra CPU consuming whilst waiting:
var nextDateStartDateTime = DateTime.Now.AddDays(1).Subtract(DateTime.Now.TimeOfDay);
double millisecondsToWait = (nextDateStartDateTime - DateTime.Now).TotalMilliseconds;
System.Threading.Timer timer = new Timer(
(o) => { Debug.WriteLine("New day comming on"); },
null,
(uint)millisecondsToWait
0);
Considering the two options you've provided:
There are 60*60*24 = 86,400 seconds per day, so you could potentially do a lot of checking if you hit the limit early. Additionally, busy waiting is a waste of CPU cycles, and it will slow down everything else that is running.
You should calculate the number of seconds until midnight and sleep that long (although I believe the sleep paramater takes ms rather than s, so a simple conversion may be needed).
EDIT:
An additional benefit of calculating then sleeping is that if a user wants to bypass your restriction by changing the clock, they will not be able to (since the clock reading midnight won't wake the process as it would with continual checking). However, with a better understanding of how your program works internally, the user could change the clock to almost midnight every time they are about to reach the limit of operations, causing the thread to wake up in a few minutes or even a few seconds. It's a more complicated exploitation than would be doable with your first suggestion, but it can be done.
This is how I make a thread sleep till tomorrow 6AM
minutesToSleep = (int)(new DateTime(DateTime.Now.AddDays(1).Year, DateTime.Now.AddDays(1).Month, DateTime.Now.AddDays(1).Day, 6, 0, 0) - DateTime.Now).TotalMinutes;
Console.WriteLine("Sleeping for {0} minutes (until tomorrow 6AM)", minutesToSleep);
精彩评论