Keep a track of time and do something at a particular time
Slow day at work, so i decide to write a small app to kill some time. It will basically be an app where the user can set a time and an action (shutdown, log off etc.).
My question is, whats the best way for my program to keep a track of time? One thing I could do 开发者_JAVA百科is compare with DateTime.now every x seconds, but that gives me a margin of error of x seconds.
Can/should I create a stopwatch and have it ticking down. When it reaches 0, it fires an event?
You could create a timer, and set its interval to the amount of time between now and when the action should occur. Then, in the OnTick event handler, perform the action (and stop the timer).
Or you can use Windows event scheduler.
What i normally do is compare DateTime.Now to the set DateTime then find the difference as a TimeSpan and then set a timer with the right interval. When the timer runs out the right action is performed.
If you take this to the next level, i did something similar which allows for DayOfTheWeek to be set, intervals and time of the day. And the service figures out which is next and triggers accoordingly.
Basically creating my own scheduled tasks windows service.
CreateWaitableTimer from WinAPI seems particularly suited for this task. I find that the resolution is good enough for most needs.
You can use the following wrapper for .NET:
public class WaitableTimer: IDisposable
{
[DllImport("kernel32.dll")]
private static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWaitableTimer(SafeWaitHandle hTimer, [In] ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);
[DllImport("kernel32.dll")]
private static extern bool CancelWaitableTimer(SafeWaitHandle hTimer);
private SafeWaitHandle _handle;
private EventWaitHandle _waitHandle;
private readonly AutoResetEvent _cancelEvent = new AutoResetEvent(false);
public WaitableTimer()
{
_handle = CreateWaitableTimer(IntPtr.Zero, true, "WaitableTimer_" + Guid.NewGuid());
_waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
_waitHandle.SafeWaitHandle = _handle;
}
public void InterruptWait()
{
_cancelEvent.Set();
}
public bool WaitUntil(DateTime eventTime)
{
long duetime = eventTime.ToFileTime();
if (SetWaitableTimer(_handle, ref duetime, 0, IntPtr.Zero, IntPtr.Zero, true))
{
return WaitHandle.WaitAny(new[] { _waitHandle, _cancelEvent }) == 0;
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
public void Dispose()
{
InterruptWait();
_handle.Dispose();
}
}
精彩评论