简体   繁体   English

EventWaitHandle。 阻塞 在C#中设置唤醒计时器

[英]EventWaitHandle. Blocking. Setting a wake up timer in C#

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading;
        using System.Runtime.InteropServices;
        using Microsoft.Win32.SafeHandles;
        using System.ComponentModel;
        using System.Windows.Forms;
        using System.Diagnostics;


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

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

            //tmParam will be converted to the proper data type inside
            //the class. Just send DateTime with the correct WakeUp time
            //As the only param to the constructor of WakeUp
            public WakeUp(DateTime tmParam)
            {
                //Create a new thread to set the waitable timer
                //setWaitable(tmParam);
                Debug.Print("Starting thread...");

                Thread t = new Thread( () => setWaitable(tmParam) );
                t.Start();

            }

            static void setWaitable(DateTime smParam)
            {
                long waketime = smParam.ToFileTime();

                using (SafeWaitHandle handle = CreateWaitableTimer(IntPtr.Zero, true, DateTime.Now.ToString()))
                {
                    //I need to try starting this block in a new thread since there is some blocking going on
                    //to set the waitable timer
                    if (SetWaitableTimer(handle, ref waketime, 0, IntPtr.Zero, IntPtr.Zero, true))
                    {
                        using (EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.AutoReset))
                        {
                            wh.SafeWaitHandle = handle;
                            wh.WaitOne();
                            Debug.Print("TimerSet "+smParam.ToString());
                        }
                    }
                    else
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
            }
        }

The new thread is created however: 但是,将创建新线程:

    Debug.Print("TimerSet "+smParam.ToString());

never gets printed to the output window. 永远不会打印到输出窗口。 It is possible to change the constructor to: 可以将构造函数更改为:

            public WakeUp(DateTime tmParam)
            {
                //Create a new thread to set the waitable timer
                //setWaitable(tmParam);
                Debug.Print("Starting thread...");

                 setWaitable(tmParam);
            } 

however this will block the current thread which takes approx two minutes or less but it works every time. 但是,这将阻塞当前线程,这大约需要两分钟或更短的时间,但每次都起作用。 I was thinking to move things onto its own thread. 我当时正在考虑将事物移到其自己的线程上。

For some reason the first way I posted when creating a new thread EventWaitHandle doesn't ever seem to come back. 由于某种原因,我在创建新线程EventWaitHandle时发布的第一种方式似乎从未回来。 Its just blocking forever I think. 我认为它永远地阻塞着。 Could this be a security issue between threads? 这可能是线程之间的安全问题吗?

Just to clarify I am calling like: 只是为了澄清我打电话像:

    WakeUp test1 = new wakeUp(DateTime.Now.AddMinutes(2));

Thank you... 谢谢...

  new wakeUp(DateTime.Now.AddMinutes(2)

The pDueTime argument of SetWaitableTimer() can be incremental or absolute. SetWaitableTimer()的pDueTime参数可以是增量的或绝对的。 You specify an incremental value by passing a negative value. 您可以通过传递负值来指定增量值。 But you are using a positive value so you get absolute time. 但是,您使用的是正值,因此您可以获得绝对的时间。 Clearly you'd be ahead if you use an incremental value since that's what you really want. 显然,如果您使用增量值,那将是领先的,因为那是您真正想要的。 Use the TimeSpan.Ticks property. 使用TimeSpan.Ticks属性。

Using absolute time is okay, but when you are in Rome then you have to act like a Roman, the operating system's clock runs on UTC. 使用绝对时间是可以的,但是当您在罗马时,您必须像罗马人那样工作,操作系统的时钟在UTC上运行。 Local time is only for humans. 当地时间仅适用于人类。 From the MSDN article for SetWaitableTimer: 从有关SetWaitableTimer的MSDN文章中:

The time after which the state of the timer is to be set to signaled, in 100 nanosecond intervals. 以100纳秒的间隔将计时器的状态设置为发出信号的时间。 Use the format described by the FILETIME structure. 使用FILETIME结构描述的格式。 Positive values indicate absolute time. 正值表示绝对时间。 Be sure to use a UTC-based absolute time , as the system uses UTC-based time internally. 确保使用基于UTC的绝对时间 ,因为系统在内部使用基于UTC的时间。 Negative values indicate relative time. 负值表示相对时间。 The actual timer accuracy depends on the capability of your hardware. 计时器的实际精度取决于硬件的能力。 For more information about UTC-based time, see System Time. 有关基于UTC的时间的更多信息,请参见系统时间。

You must use DateTime.UtcNow 您必须使用DateTime.UtcNow

Why are you creating a new thread for the timer? 为什么要为计时器创建新线程? The whole point of timers, WaitableTimer included, is that you create the timer object and it notifies you asynchronously (by calling a callback function on a separate thread). 计时器(包括WaitableTimer的全部要点是创建计时器对象,并异步通知您(通过在单独的线程上调用回调函数)。 when the timer period has elapsed. 计时器时间已过时。 In that regard, WaitableTimer is no different than the .NET timer object System.Threading.Timer . 在这方面, WaitableTimer与.NET计时器对象System.Threading.Timer并无不同。 In the case of WaitableTimer , you can have it signal an event, which is a handy thing. 对于WaitableTimer ,您可以让它发出事件信号,这很方便。

Some years ago I wrote an article about using the WaitableTimer from C#. 几年前,我写了一篇有关使用C#中的WaitableTimer的文章。 Unfortunately, the site that hosted the article is no longer in existence. 不幸的是,托管该文章的站点已不存在。 The code is available, with examples, from http://mischel.com/pubs/waitabletimer.zip . 可以从http://mischel.com/pubs/waitabletimer.zip中获得示例代码。

You probably want to review the Thread Timer Example , which shows how timers are typically used. 您可能想查看Thread Timer Example ,它显示了通常如何使用计时器。 The mechanism for the WaitableTimer is slightly different, but the concepts are the same. WaitableTimer的机制略有不同,但是概念相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM