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

  运行结果如下:

  

  

 

转载于:https://www.cnblogs.com/3xiaolonglong/p/9650908.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值