WaitHandle:

命名空间:System.Threading
封装等待对共享资源进行独占访问的操作系统特定的对象。 WaitHandle:是一个抽象类,我们一般不直接用,而是用它的派生类:

  1. AutoResetEvent
  2. EventWaitHandle
  3. ManualResetEvent
  4. Mutex
  5. Semaphore

详细信息请点击微软链接:WaitHandle

一 AutoResetEvent:

表示线程同步事件在一个等待线程释放后收到信号时自动重置。 此类不能被继承。

构造函数:
构造函数描述
AutoResetEvent(Boolean)用一个指示是否将初始状态设置为终止的布尔值初始化 AutoResetEvent 类的新实例。
常用方法 :
方法描述
Close()释放由当前 WaitHandle 占用的所有资源。
Dispose()释放由当前 WaitHandle 占用的所有资源。
WaitOne()阻止当前线程,直到当前 WaitHandle 收到信号。
WaitOne(Int32)阻止当前线程,直到当前 WaitHandle 收到信号,同时使用 32 位带符号整数指定时间间隔(以毫秒为单位)。
WaitOne(Int32, Boolean)阻止当前线程,直到当前的 WaitHandle 收到信号为止,同时使用 32 位带符号整数指定时间间隔,并指定是否在等前退出同步域。
属性:
属性描述
Handle获取或设置本机操作系统句柄。
SafeWaitHandle获取或设置本机操作系统句柄。
字段:
字段描述
WaitTimeout指示在任何等待句柄终止之前 WaitAny(WaitHandle[], Int32, Boolean) 操作已超时。 此字段为常数。

官方链接:AutoResetEvent

常用派生类

1. AutoResetEvent:

表示线程同步事件在一个等待线程释放后收到信号时自动重置。 此类不能被继承。
是一个自动阻塞,WaitOne() 方法阻塞程序执行,Set() 方法释放信息。当释放后阻塞的代码继续执行。但下一次执行还需要等待信号。
通俗的讲,WaitOne()是关门,Set()是开门。但开门之后。执行完又自动关上了,还需要开门。还可以指定超时时间:

 are.WaitOne(1000);//指定超时一秒,如果一秒后没有信号程序继续执行

示例Dome:

 static void Main(string[] args)
        {
            AutoResetEvent are = new AutoResetEvent(false); //初始状态为关,构造函数传入 false
            Thread t1 = new Thread(() => {
                    Console.WriteLine("开始等着开门");
                    are.WaitOne();
                    Console.WriteLine("终于等到你");
            });
            t1.IsBackground = true;
            t1.Start();

            Console.WriteLine("按任意键开门");
            Console.ReadKey();
            are.Set();//开门
            Console.ReadKey();
        }

重要:

此类实现了 IDisposable 接口。 在使用完类型后,您应直接或间接释放类型。 若要直接释放类型,请在 try/catch 块中调用其 Dispose 方法。 若要间接释放类型,请使用 using(在 C# 中)

不保证每次调用Set方法都将释放一个线程。 如果两次调用都过于接近, 因此在释放线程之前发生第二次调用, 则只释放一个线程。 这就像第二次调用没有发生。 此外, 如果Set在没有等待的线程并且已发出信号的AutoResetEvent情况下调用, 则调用不起作用。

详细信息官方链接:AutoResetEvent

2. ManualResetEvent:

表示线程同步事件,收到信号时,必须手动重置该事件。 此类不能被继承。
与AutoResetEvent类刚好相反,ManualResetEvent是一旦设定Set()后就一直开门,除非调用Reset()关门。Manual:手动;Reset:关门。

示例Dome:

       static void Main(string[] args)
        {
            //WaitOne()还可以设置等待超时时间:
            ManualResetEvent m = new ManualResetEvent(false);
            Thread t1 = new Thread(()=> {
                Console.WriteLine("等着开门");
                if(m.WaitOne(5000))
                {
                    Console.WriteLine("终于等到你了");
                }
                else
                {
                    Console.WriteLine("登录5秒还没等到你");
                }
            });
            t1.Start();
            Console.WriteLine("按任意键开门");
            Console.ReadKey();
            m.Set();//开门
            Console.WriteLine("终于开门了");
            Console.ReadKey();

        }

详细信息官方链接:ManualResetEvent

WaitHandle.WaitAll(WaitHandle[] waitHandles)用来等待所有信号都变为“开门状态”,WaitHandle. WaitAny(WaitHandle[] waitHandles) 用来等待任意一个信号都变为“开门状态”。

3.EventWaitHandle

表示一个线程同步事件。
EventWaitHandle 的功能结合了前面两种。在构造函数中传入不同的参数,就会又不同的功能。

 class Program
    {

        //EventWaitHandle用于演示自动重置和手动重置同步事件之间的区别。
        private static EventWaitHandle ewh;

        //一个计数器,确保在释放任何线程之前启动和阻塞所有线程。Long用于显示64位互锁方法的使用。
        private static long threadCount = 0;

        //一个自动重置事件,该事件允许主线程阻塞,直到退出的线程减少计数为止。
        private static EventWaitHandle clearCount = new EventWaitHandle(false, EventResetMode.AutoReset);

        [MTAThread]
        public static void Main()
        {
            //创建一个自动重置EventWaitHandle。
            ewh = new EventWaitHandle(false, EventResetMode.AutoReset);

            // 创建并启动五个编号的线程。使用ParameterizedThreadStart委托,这样线程号就可以作为参数传递给Start方法。
            for (int i = 0; i <= 4; i++)
            {
                Thread t = new Thread(
                    new ParameterizedThreadStart(ThreadProc)
                );
                t.Start(i);
            }
            //等待,直到所有线程都已启动和阻塞。当多个线程在32位系统上使用64位值时,必须通过联锁类访问该值,以确保线程安全。
            while (Interlocked.Read(ref threadCount) < 5)
            {
                Thread.Sleep(500);
            }

            //每次用户按回车键释放一个线程,直到所有线程都被释放。
            while (Interlocked.Read(ref threadCount) > 0)
            {
                Console.WriteLine("按ENTER键释放一个等待线程。");
                Console.ReadLine();

                //SignalAndWait向EventWaitHandle发出信号,EventWaitHandle在重置之前只释放一个线程,因为它是用AutoReset模式创建的。然后阻塞clearCount,以允许发出信号的线程在再次循环之前递减计数。
                WaitHandle.SignalAndWait(ewh, clearCount);
            }
            Console.WriteLine();

            //创建一个ManualReset EventWaitHandle。
            ewh = new EventWaitHandle(false, EventResetMode.ManualReset);

            //创建并启动另外五个编号的线程。
            for (int i = 0; i <= 4; i++)
            {
                Thread t = new Thread(
                    new ParameterizedThreadStart(ThreadProc)
                );
                t.Start(i);
            }

            //等待,直到所有线程都已启动和阻塞。
            while (Interlocked.Read(ref threadCount) < 5)
            {
                Thread.Sleep(500);
            }

            //因为EventWaitHandle是用ManualReset模式创建的,它发出释放所有等待线程的信号。
            Console.WriteLine("按ENTER键释放等待的线程。");
            Console.ReadLine();
            ewh.Set();

            Console.ReadKey();
        }

        public static void ThreadProc(object data)
        {
            int index = (int)data;

            Console.WriteLine("Thread {0} blocks.", data);
            //增加阻塞线程的数量。
            Interlocked.Increment(ref threadCount);

            // 等着EventWaitHandle.
            ewh.WaitOne();

            Console.WriteLine("Thread {0} exits.", data);
            //减少阻塞线程的数量。
            Interlocked.Decrement(ref threadCount);

            //发出ewh信号后,主线程阻塞clearCount,直到发出信号的线程减少了计数。现在信号。
            clearCount.Set();
        }
    }

在这里插入图片描述

详细信息官方链接:EventWaitHandle

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐