• C#多线程---Event类实现线程同步


    一、简介

    我们使用类(.net Framework中的类,如 AutoResetEvent, Semaphore类等)的方法来实现线程同步的时候,其实内部是调用操作系统的内核对象来实现的线程同步。

    System.Threading命名空间中提供了一个WaitHandle 的抽象基类,此类就是包装了一个Windows内核对象的句柄(句柄可以理解为标示了对象实例的一个数字),在.net Framework中提供了从WaitHandle类中派生的类。继承关系如下所示:

    WaitHandle

      EventWaitHandle

           AutoResetEvent

         ManualResetEvent

      Semaphore

      Mutex

    当我们在使用 AutoResetEvent,ManualResetEvent,Semaphore,Mutex这些类的时候,用构造函数来实例化这些类的对象时,其内部都调用了Win32 CreateEvent或CreateEvent函数,或CreateSemaphore或者CreateMutex函数,这些函数调用返回的句柄值都保存在WaitHandle基类定义的SafeWaitHandle字段中。

    二、AutoResetEvent (自动重置事件)

    AutoResetEvent 在获得信号后,会自动将事件设置为无信号状态。

      例1:事件初始化为无信号状态,主线程等待一段时间将事件设置为有信号状态

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading;
     6 using System.Threading.Tasks;
     7 
     8 namespace ThreadEvent
     9 {
    10     class Program
    11     {
    12         public static AutoResetEvent autoEvent = new AutoResetEvent(false);
    13         static void Main(string[] args)
    14         {
    15             Task task = new Task(ThreadFunc);
    16             task.Start();
    17             Console.WriteLine($"{DateTime.Now} Printed in main");
    18             Thread.Sleep(5000);
    19             Console.WriteLine($"{DateTime.Now} Set signal in main");
    20             autoEvent.Set();
    21             Console.Read();
    22         }
    23         private static void ThreadFunc()
    24         {
    25             PrintThreadInfo($"Printed in thread func");
    26         }
    27         private static void PrintThreadInfo(string info)
    28         {
    29             if (autoEvent.WaitOne())
    30             {
    31                 //autoEvent.WaitOne();
    32                 Console.WriteLine($"{DateTime.Now} {info}");
    33                 Console.WriteLine($"{DateTime.Now} ThreadId:{Thread.CurrentThread.ManagedThreadId}
    IsBackgroundThread:{Thread.CurrentThread.IsBackground}
    IsThreadPoolThread:{Thread.CurrentThread.IsThreadPoolThread}");
    34             }
    35         
    36         }
    37     }
    38 }
    View Code

      运行结果如下:

      

      例2:事件初始化为无信号状态,主线程等待一段时间将事件设置为有信号状态,子线程连续两次Wait,观察第二次Wait的结果 

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading;
     6 using System.Threading.Tasks;
     7 
     8 namespace ThreadEvent
     9 {
    10     class Program
    11     {
    12         public static AutoResetEvent autoEvent = new AutoResetEvent(false);
    13         static void Main(string[] args)
    14         {
    15             Task task = new Task(ThreadFunc);
    16             task.Start();
    17             Console.WriteLine($"{DateTime.Now} Printed in main");
    18             Thread.Sleep(5000);
    19             Console.WriteLine($"{DateTime.Now} Set signal in main");
    20             autoEvent.Set();
    21             Console.Read();
    22         }
    23         private static void ThreadFunc()
    24         {
    25             PrintThreadInfo($"Printed in thread func");
    26         }
    27         private static void PrintThreadInfo(string info)
    28         {
    29             if (autoEvent.WaitOne())
    30             {
    31                 if (autoEvent.WaitOne(4000))
    32                 {
    33                     Console.WriteLine($"{DateTime.Now} {info}");
    34                     Console.WriteLine($"{DateTime.Now} ThreadId:{Thread.CurrentThread.ManagedThreadId}
    IsBackgroundThread:{Thread.CurrentThread.IsBackground}
    IsThreadPoolThread:{Thread.CurrentThread.IsThreadPoolThread}");
    35                 }
    36                 else
    37                 {
    38                     Console.ForegroundColor = ConsoleColor.Red;
    39                     Console.WriteLine($"{DateTime.Now} WaitOne timeout!");
    40                     Console.ResetColor();
    41                 }
    42             }
    43         
    44         }
    45     }
    46 }
    View Code

      运行结果如下:

      

    三、ManualResetEvent(手动重置事件)

    ManualResetEvent在获得信号后,会一直保持有信号状态,除非我们手动调用Reset来将事件设置为无信号状态。

      例1: 

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading;
     6 using System.Threading.Tasks;
     7 
     8 namespace ThreadEvent
     9 {
    10     class Program
    11     {
    12         public static ManualResetEvent autoEvent = new ManualResetEvent(false);
    13         static void Main(string[] args)
    14         {
    15             Task task = new Task(ThreadFunc);
    16             task.Start();
    17             Console.WriteLine($"{DateTime.Now} Printed in main");
    18             Thread.Sleep(5000);
    19             Console.WriteLine($"{DateTime.Now} Set signal in main");
    20             autoEvent.Set();
    21             Console.Read();
    22         }
    23         private static void ThreadFunc()
    24         {
    25             PrintThreadInfo($"Printed in thread func");
    26         }
    27         private static void PrintThreadInfo(string info)
    28         {
    29             if (autoEvent.WaitOne())
    30             {
    31                 //autoEvent.Reset();
    32                 if (autoEvent.WaitOne(4000))
    33                 {
    34                     Console.WriteLine($"{DateTime.Now} {info}");
    35                     Console.WriteLine($"{DateTime.Now} ThreadId:{Thread.CurrentThread.ManagedThreadId}
    IsBackgroundThread:{Thread.CurrentThread.IsBackground}
    IsThreadPoolThread:{Thread.CurrentThread.IsThreadPoolThread}");
    36                 }
    37                 else
    38                 {
    39                     Console.ForegroundColor = ConsoleColor.Red;
    40                     Console.WriteLine($"{DateTime.Now} WaitOne timeout!");
    41                     Console.ResetColor();
    42                 }
    43             }
    44         
    45         }
    46     }
    47 }
    View Code

      运行结果如下:

      

      

  • 相关阅读:
    Python Tkinter canvas oval原理
    ButterKnife你需要知道的点
    RecyclerView不同类型Item的展示
    PNG图片小结
    安装应用
    java.io.IOException: open failed: ENOENT (No such file or directory)open failed: EISDIR (Is a directory)
    YouTube视频插入Markdown
    Android icons集合
    vue动态绑定类样式ClassName知多少
    js正则表达式中的正向肯定预查和正向否定预查
  • 原文地址:https://www.cnblogs.com/3xiaolonglong/p/9650908.html
Copyright © 2020-2023  润新知