在WaitAny()中使用WaitHandles数组

时间:2014-06-30 23:48:05

标签: c# autoresetevent waithandle

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

namespace ConsoleApplication1
{
    class Program
    {
        class WakeUp
        {

            public static SafeWaitHandle[] tSafeWaitHandles = new SafeWaitHandle[6];
            public static WaitHandle[][] waitHandles = new WaitHandle[6][];

            bool rslt;

            //Various imports of kernel32.dll so the waitable timer can be set
            //on the system
            [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);

            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern bool CancelWaitableTimer(SafeWaitHandle hTimer);

            //SafeHandle.DangerousGetHandle Method
            [DllImport("kernel32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CloseHandle(IntPtr hObject);

            //The constructor will use a TimeSpan to set a waitable timer
            public WakeUp(string wtName, int alarmNum)
            {
                tSafeWaitHandles[alarmNum] = CreateWaitableTimer(IntPtr.Zero, true, wtName);
            }

            public int initWakeUp(TimeSpan smParam, int alarmNum)
            {
                //The number of ticks needs to be negated to set a waitable timer in this fashion
                long waketicks = -smParam.Ticks;
                rslt = SetWaitableTimer(tSafeWaitHandles[alarmNum], ref waketicks, 0, IntPtr.Zero, IntPtr.Zero, true);
                return Convert.ToInt32(rslt);
            }

            public int DoWork(int alarmNum)
            {
                waitHandles[0] = new WaitHandle[] 
                {
                    new AutoResetEvent(false),
                    new AutoResetEvent(false)
                };


                waitHandles[alarmNum][0].SafeWaitHandle = tSafeWaitHandles[alarmNum];

                WaitHandle.WaitAny(waitHandles[alarmNum]);

                Thread.Sleep(5000);


                return 0;
            }

        } 

        static void Main(string[] args)
        {
            Console.WriteLine( DateTime.Now );

            WakeUp temp = new WakeUp("spalarm1", 0);
            temp.initWakeUp(TimeSpan.FromMinutes(1), 0);
            temp.DoWork(0);

            //I would like an optional Set which will cause DoWork to stop blocking
            //when set is called. Is this possible to do?
            //WakeUp.waitHandles[0][1].Set();

            Console.WriteLine(DateTime.Now);
            Console.WriteLine("Done...");
            Console.ReadKey();
        }
    }
}

该程序设置一个等待计时器。那部分工作正常。线程阻塞,直到定时器触发。我想做的是能够在其中一个WaitHandles上调用.Set来释放阻塞的线程。似乎这个代码编写的方式.Set不可用,所以我现在就注释掉了。我需要能够调用其中一个定时器来释放阻塞的线程。有谁知道怎么做?

我现在遇到的问题是我打算用以下方式结束:

  

错误1'System.Threading.WaitHandle'不包含'Set'的定义,也没有扩展方法'Set'接受类型'System.Threading.WaitHandle'的第一个参数可以找到(你是否错过了使用指令或程序集引用?)C:\ Users \ Eric \ Documents \ Visual Studio 2013 \ Projects \ waitany \ ConsoleApplication1 \ Program.cs 86 38 ConsoleApplication1

1 个答案:

答案 0 :(得分:1)

Set方法在EventWaitHandleAutoResetEventManualResetEvent的基类)中声明,而不在WaitHandle中声明。由于WakeUp类将AutoResetEvent公开为WaitHandles数组,因此您无法直接在其上调用Set。无论如何,更简洁的方法是在WakeUp类中添加一个特定的方法来设置等待句柄;公开揭露他们的封装。