#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
класс для установки дескрипторов ожидания; их публичное раскрытие нарушает инкапсуляцию.