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}\nIsBackgroundThread:{Thread.CurrentThread.IsBackground}\nIsThreadPoolThread:{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}\nIsBackgroundThread:{Thread.CurrentThread.IsBackground}\nIsThreadPoolThread:{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}\nIsBackgroundThread:{Thread.CurrentThread.IsBackground}\nIsThreadPoolThread:{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

  運行結果如下:

  

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM