一、简介

我们使用类(.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 }

  运行结果如下:

  

  例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 }

  运行结果如下:

  

三、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 }

  运行结果如下:

  

  

C#多线程---Event类实现线程同步的更多相关文章

  1. C#多线程---Mutex类实现线程同步

    一.例子 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 ...

  2. C#多线程:深入了解线程同步lock,Monitor,Mutex,同步事件和等待句柄(中)

    本篇继续介绍WaitHandler类及其子类 Mutex,ManualResetEvent,AutoResetEvent的用法..NET中线程同步的方式多的让人看了眼花缭乱,究竟该怎么去理解呢?其实, ...

  3. Python多线程(2)——线程同步机制

    本文介绍Python中的线程同步对象,主要涉及 thread 和 threading 模块. threading 模块提供的线程同步原语包括:Lock.RLock.Condition.Event.Se ...

  4. java多线程(2) 线程同步

    我们对线程访问同一份资源的多个线程之间,来进行协调的这个东西,就是线程同步.   例子1:模拟了多个线程操作同一份资源,可能带来的问题: package com.cy.thread; public c ...

  5. Java多线程系列三——实现线程同步的方法

    两种实现线程同步的方法 方法 特性 synchronized 不需要显式地加解锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 ...

  6. Java多线程之简单的线程同步实例

    数据类: package Thread.MyCommon; public class Data { public int num = 0; public synchronized int getEve ...

  7. iOS多线程各种安全锁介绍 - 线程同步

    一.atomic介绍 github对应Demo:https://github.com/Master-fd/LockDemo 在iOS中,@property 新增属性时,可以增加atomic选项,ato ...

  8. win32多线程 (二)线程同步之临界区 (critical sections)

    所谓critical sections 意指一小块“用来处理一份被共享之资源”的程序代码.你可能必须在程序的许多地方处理这一块可共享的资源.所有这些程序代码可以被同一个critical  sectio ...

  9. C#线程学习笔记五:线程同步--事件构造

    本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/23/Event_Constructor.html,记录一下学习过程以备后续查用. 前面讲的线 ...

随机推荐

  1. [008] - JavaSE面试题(八):集合

    第一期:Java面试 - 100题,梳理各大网站优秀面试题.大家可以跟着我一起来刷刷Java理论知识 [008] - JavaSE面试题(八):集合 第1问:说一下集合的体系? 单列集合: 双列集合: ...

  2. 达梦数据库(DM8)大规模并行集群MPP 2节点安装部署

    达梦数据库大规模并行集群MPP 2节点安装部署   1.环境准备   os 数据库版本 ip mpp角色 centos7.x86 DM8 192.168.30.100 mpp1 centos7.x86 ...

  3. 42 张图带你撸完 MySQL 优化

    Hey guys,这里是程序员cxuan,欢迎你阅读我最新一期的文章,这篇文章是 MySQL 调优的汇总版,我加了一下日常开发过程中的调优经验,希望对各位小伙伴们有所帮助.下面开始正文. 一般传统互联 ...

  4. 简单快速安装Apache+PHP+MySql服务环境(三)—— 下载安装phpmyadmin

    为了方便在Linux上操作mysql数据库,打算安装一个phpmyadmin,不过在下载安装的过程中出现了一些坑,特此记录. 1. 在官网上下载phpmyadmin https://files.php ...

  5. 每天五分钟Go - 闭包

    闭包的示例代码 func getSequence() func() int{ i:=0 return func() int { i+=1 return i } } 首先,函数名getSequence, ...

  6. P5147-数学-随机数生成器

    P5147-数学-随机数生成器 (洛谷第一篇题解说这是高一数学题,新高二感觉到被吊打) 我们设work(x)的期望值为\(f_x\) 注意\(f_1\)是边界.不过对下列式子没有影响.原因参照必修的数 ...

  7. odoo12动作里添加向导

    在odoo12的 动作里添加向导例子1:只会在tree视图里显示,不会在form里显示 <act_window id="action_change_stage_ttest" ...

  8. 第十九篇 -- QTableWidget的使用

    QTableWidget的一些常用方法 下面两个类可以根据自己的情况自定义. 单元格类型的类: class CellType(Enum): ctKey = 1000 ctPath = 1001 ctI ...

  9. Oracle12c至少开启的服务

    如图,至少开启这两个服务才能运行

  10. 当vue 页面加载数据时显示 加载loading

    参考:https://www.jianshu.com/p/104bbb01b222 Vue 页面加载数据之前增加 `loading` 动画 创建组件 1.新建 .vue 文件: src -> c ...