Использование массива WaitHandles с помощью WaitAny()

#c# #autoresetevent #waithandle

#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 rs<

            //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 ‘Система.Многопоточность.WaitHandle’ не содержит определения для ‘Set’ и никакого метода расширения ‘Set’, принимающего первый аргумент типа ‘System.Многопоточность.Удалось найти WaitHandle’ (вам не хватает директивы using или ссылки на сборку?) C:UsersEricDocumentsVisual Studio 2013ProjectswaitanyConsoleApplication1Program.cs 86 38 ConsoleApplication1

Ответ №1:

Set Метод объявлен в EventWaitHandle (базовый класс для AutoResetEvent и ManualResetEvent ), а не в WaitHandle . Поскольку WakeUp класс предоставляет AutoResetEvent s в виде массива WaitHandles , вы не можете вызывать Set их напрямую. В любом случае, более чистым подходом было бы добавить определенный метод в WakeUp класс для установки дескрипторов ожидания; их публичное раскрытие нарушает инкапсуляцию.