7

在非托管 Win32 世界中,我习惯于使用CreateWaitableTimer API 创建的可等待计时器,这些计时器可用于同步调用,例如WaitForSingleObject,主要用于WaitForMultipleObjects

.NET 和 C# 中必须有一个可等待计时器的模拟?

4

1 回答 1

6

你需要等待计时器做什么?

.NET 中“我可以等待的东西”的默认类是System.Threading.Tasks.Task. 在 .NET 4.5 中,您可以简单地使用Task.Delay(milliseconds).

在 .NET 4.0 中,您可以使用 aTaskCompletionSource创建任务,并使用普通计时器将其设置为已完成。或者使用Async Targeting PackAsyncBridgeTaskEx.Delay中的实现

如果您需要实际的WaitHandle,您可以使用ManualResetEvent, 并使用普通的 .NET 计时器来设置事件。

或者,您可以创建自己的派生自WaitHandleP/Invoke的类CreateWaitableTimer。.NET 框架中似乎已经存在这样的类,但它是内部的。(System.Runtime.IOThreadTimer.WaitableTimer来自System.ServiceModel.Internals.dll

public class WaitableTimer : WaitHandle
{
    [DllImport("kernel32.dll")]
    static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool SetWaitableTimer(SafeWaitHandle hTimer, [In] ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, [MarshalAs(UnmanagedType.Bool)] bool fResume);

    public WaitableTimer(bool manualReset = true, string timerName = null)
    {
        this.SafeWaitHandle = CreateWaitableTimer(IntPtr.Zero, manualReset, timerName);
    }

    public void Set(long dueTime)
    {
        if (!SetWaitableTimer(this.SafeWaitHandle, ref dueTime, 0, IntPtr.Zero, IntPtr.Zero, false))
        {
            throw new Win32Exception();
        }
    }
}
于 2013-04-07T04:47:00.527 回答