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

  运行结果如下:

  

  

原文地址:https://www.cnblogs.com/3xiaolonglong/p/9650908.html