1
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 の 1 つで .Set を呼び出して、スレッドをブロックから解放できるようにすることです。このコードの .Set の書き方は利用できないようですので、今のところその行をコメントアウトしました。スレッドのブロックを解除するには、タイマーの 1 つを呼び出す必要があります。誰もこれを行う方法を知っていますか?

私が今抱えている問題は、 set への呼び出しが次のように終わることです:

エラー 1 'System.Threading.WaitHandle' には 'Set' の定義が含まれておらず、タイプ 'System.Threading.WaitHandle' の最初の引数を受け入れる拡張メソッド 'Set' が見つかりませんでした (using ディレクティブまたはアセンブリ参照?) C:\Users\Eric\Documents\Visual Studio 2013\Projects\waitany\ConsoleApplication1\Program.cs 86 38 ConsoleApplication1

4

1 に答える 1

1

Setメソッドはではなく ( と の基本クラス) で宣言さEventWaitHandleれます。クラスはの配列として s を公開するため、それらを直接呼び出すことはできません。とにかく、よりクリーンなアプローチは、クラスに特定のメソッドを追加して待機ハンドルを設定することです。それらを公に公開すると、カプセル化が解除されます。AutoResetEventManualResetEventWaitHandleWakeUpAutoResetEventWaitHandlesSetWakeUp

于 2014-07-01T00:16:07.033 に答える