• C# 应用


    1. 类的关系

    1. AutoResetEvent 和 ManualResetEvent 都继承自 System.Threading.EventWaitHandle 类(EventWaitHandle 继承自 WaitHandle);
    2. 用于线程交互 (或线程信号)

    2. 常用方法

    2.1 WaitHandle 几个常用的方法

    1. public virtual bool WaitOne(int millisecondsTimeout); //阻止当前线程 ,直到当前 System.Threading.WaitHandle 收到信号,或直到 millisecondsTimeout 后。
    2. public virtual bool WaitOne(); //阻止当前线程,直到当前 System.Threading.WaitHandle 收到信号。
    3. public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout);
    4. public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout);

    2.2 EventWaitHandle 几个常用的方法

    1. public bool Set();
      将事件设置为有信号,从而允许一个或多个等待线程继续执行
    2. public bool Reset();
      将事件设置为非终止状态,从而导致线程受阻

    2.3 AutoResetEvent

    1. 该类的定义:通知正在等待的线程已发生事件
    2. public AutoResetEvent(bool initialState); //initialState 指是否将初始状态设置为终止状态的类

    2.4 ManualResetEvent

    1. 该类的定义:通知一个或多个正在等待的线程已发生事件
    2. public ManualResetEvent(bool initialState);

    3. 使用逻辑

    3.1 AutoResetEvent 的使用逻辑

    1. 实例化 AutoResetEvent 时,需要设置初始状态是否为终止状态;
    2. 若遇到状态为非终止状态的 AutoResetEvent 的 Wait 系列方法(如 WaitOne()),将 阻止当前线程继续往下执行,直到当前 AutoResetEvent 收到信号;
    3. 收到信号后,保持终止状态并释放一个等待线程,让其继续往下执行,然后自动返回非终止状态。

    3.2 ManualResetEvent 的使用逻辑

    1. 实例化 ManualResetEvent 时,需要设置初始状态是否为终止状态;
    2. 若遇到状态为非终止状态的 ManualResetEvent 的 Wait 系列方法(如 WaitOne()),将 阻止当前线程继续往下执行,直到当前 ManualResetEvent 收到信号;
    3. 收到信号后,所有等待线程都被释放,可以继续往下执行;
    4. 跟 AutoResetEvent 不同的是,收到信号后,ManualResetEvent 将继续保持信号,直到通过手动调用 Reset() 方法重置 ManualResetEvent 的状态为非终止。

    4. 例子

    4.1 AutoResetEvent

    using System;
    using System.Threading;
    
    class Example
    {
        private static AutoResetEvent event_1 = new AutoResetEvent(true);
        private static AutoResetEvent event_2 = new AutoResetEvent(false);
    
        static void Main()
        {
            for (int i = 1; i < 4; i++)
            {
                Thread t = new Thread(ThreadProc);
                t.Name = "Thread_" + i;
                t.Start();
            }
            Thread.Sleep(250);
    
            for (int i = 0; i < 2; i++)
            {
                Console.WriteLine("按任意键释放另一个线程");
                Console.ReadLine();
                event_1.Set();
                Thread.Sleep(250);
            }
    
            Console.WriteLine("
    至此所有线程都在等待 AutoResetEvent #2.");
            
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine("按任意键释放另一个线程");
                Console.ReadLine();
                event_2.Set();
                Thread.Sleep(250);
            }
        }
    
        static void ThreadProc()
        {
            string name = Thread.CurrentThread.Name;
    
            Console.WriteLine("{0} 等待 AutoResetEvent #1.", name);
            event_1.WaitOne();
            Console.WriteLine("{0} 被 AutoResetEvent #1 释放.", name);
    
            Console.WriteLine("{0} 等待 AutoResetEvent #2.", name);
            event_2.WaitOne();
            Console.WriteLine("{0} 被 from AutoResetEvent #2 释放.", name);
    
            Console.WriteLine("{0} 结束.", name);
        }
    }
    
    /* 上面例子将输出如下:
    
    Thread_1 等待 AutoResetEvent #1.
    Thread_1 被 AutoResetEvent #1 释放.
    Thread_1 等待 AutoResetEvent #2.
    Thread_2 等待 AutoResetEvent #1.
    Thread_3 等待 AutoResetEvent #1.
    按任意键释放另一个线程
    
    Thread_2 被 AutoResetEvent #1 释放.
    Thread_2 等待 AutoResetEvent #2.
    按任意键释放另一个线程
    
    Thread_3 被 AutoResetEvent #1 释放.
    Thread_3 等待 AutoResetEvent #2.
    
    至此所有线程都在等待 AutoResetEvent #2.
    按任意键释放另一个线程.
    
    Thread_1 被 from AutoResetEvent #2 释放.
    Thread_1 结束.
    按任意键释放另一个线程.
    
    Thread_2 被 from AutoResetEvent #2 释放.
    Thread_2 结束.
    按任意键释放另一个线程.
    
    Thread_3 被 from AutoResetEvent #2 释放.
    Thread_3 结束.
     */
    

    4.2 ManualResetEvent

    using System;
    using System.Threading;
    
    public class Example
    {
        private static ManualResetEvent mre = new ManualResetEvent(false);
    
        static void Main()
        {
            Console.WriteLine("
    开启 3 个被 ManualResetEvent 阻塞的线程
    ");
            
            for (int i = 0; i <= 2; i++)
            {
                Thread t = new Thread(ThreadProc);
                t.Name = "Thread_" + i;
                t.Start();
            }
            
            Thread.Sleep(500);
            Console.WriteLine("
    所有线程已开启,请按下 enter 键发送信号从而一次性释放所有线程
    ");
            Console.ReadLine();
            
            mre.Set();
            
            Thread.Sleep(500); // 主线程等待 500 毫秒让子线程先执行完毕
            
            Console.WriteLine("
    当 ManualResetEvent 是有信号时,即使遇到 WaitOne() 也不会被阻塞:
    ");
            
            for (int i = 3; i <= 4; i++)
            {
                Thread t = new Thread(ThreadProc);
                t.Name = "Thread_" + i;
                t.Start();
            }
            
            Thread.Sleep(500);
            Console.WriteLine("
    请按下 enter 键盘触发 Reset() 方法, 从而后面的线程在遇到 WaitOne() 时继续被阻塞.
    ");
            Console.ReadLine();
            
            mre.Reset();
            
            Thread t5 = new Thread(ThreadProc);
            t5.Name = "Thread_5";
            t5.Start();
            
            Thread.Sleep(500);
            Console.WriteLine("
    请按下 enter 键发送信号.");
            Console.ReadLine();
            
            mre.Set();
            
            Console.ReadLine();
        }
    
        private static void ThreadProc()
        {
            string name = Thread.CurrentThread.Name;
    
            Console.WriteLine(name + " starts and calls mre.WaitOne()");
    
            mre.WaitOne();
    
            Console.WriteLine(name + " ends.");
        }
    }
    
    /* 上面例子将输出如下:
    
    开启 3 个被 ManualResetEvent 阻塞的线程
    
    Thread_0 starts and calls mre.WaitOne()
    Thread_1 starts and calls mre.WaitOne()
    Thread_2 starts and calls mre.WaitOne()
    
    所有线程已开启,请按下 enter 键发送信号从而一次性释放所有线程
    
    
    Thread_0 ends.
    Thread_1 ends.
    Thread_2 ends.
    
    当 ManualResetEvent 是有信号时,即使遇到 WaitOne() 也不会被阻塞:
    
    Thread_3 starts and calls mre.WaitOne()
    Thread_3 ends.
    Thread_4 starts and calls mre.WaitOne()
    Thread_4 ends.
    
    请按下 enter 键盘触发 Reset() 方法, 从而后面的线程在遇到 WaitOne() 时继续被阻塞.
    
    
    Thread_5 starts and calls mre.WaitOne()
    
    请按下 enter 键发送信号.
    
    Thread_5 ends.
     */
    
  • 相关阅读:
    Google布隆过滤器与Redis布隆过滤器详解
    这个面试问题很难么 | 如何处理大数据中的数据倾斜
    阿里巴巴微服务架构演进
    快手HBase在千亿级用户特征数据分析中的应用与实践
    基于Kafka+Flink+Redis的电商大屏实时计算案例
    阿里云E-MapReduce产品探秘,快速构建可扩展的高性能大数据平台
    阿里云Spark Shuffle的优化
    Flink CheckPoint奇技淫巧 | 原理和在生产中的应用
    你需要的不是实时数仓 | 你需要的是一款合适且强大的OLAP数据库(上)
    你需要的不是实时数仓 | 你需要的是一款强大的OLAP数据库(下)
  • 原文地址:https://www.cnblogs.com/MichaelLoveSna/p/14507513.html
Copyright © 2020-2023  润新知