ManualResetEvent、AutoResetEvent和Mutex

简介: 这三个东西若不是经常使用,我想也没人记得住它们各自的作用和相互的区别。我以前总是在用到它们的时候再回头温习一遍,每次温习的经历都不是像见到老朋友般如沐春风,而是难以名状的烦躁和郁闷。今天又遇到需要使用它们的时候,为了以后不再痛苦,我便将关于它们的要点记录下来。

这三个东西若不是经常使用,我想也没人记得住它们各自的作用和相互的区别。我以前总是在用到它们的时候再回头温习一遍,每次温习的经历都不是像见到老朋友般如沐春风,而是难以名状的烦躁和郁闷。今天又遇到需要使用它们的时候,为了以后不再痛苦,我便将关于它们的要点记录下来。

编程编的久了,总会遇到多线程的情况,有些时候我们要几个线程合作完成某个功能,这时候可以定义一个全局对象,各个线程根据这个对象的状态来进行各自的工作。ManualResetEvent、AutoResetEvent和Mutex就相当于这样的一种对象类型,而它们的作用类似,也比较单一,就是阻塞相关线程和取消阻塞相关线程。

以下这段话和代码摘自ManualResetEvent和AutoResetEvent的区别

ManualResetEvent可以阻塞一个或多个线程,直到收到一个信号告诉ManualResetEvent不要再阻塞当前的线程。 

可以想象ManualResetEvent这个对象内部有一个Boolean类型的属性IsRelease来控制是否要阻塞当前线程。这个属性我们在初始化的时候可以设置它,如ManualResetEvent event=new ManualResetEvent(false);这就表明默认的属性是要阻塞当前线程。

代码举例:

 1 ManualResetEvent _manualResetEvent = new ManualResetEvent(false);  
 2     
 3 private void BT_Temp_Click(object sender, RoutedEventArgs e)  
 4 {  
 5     Thread t1 = new Thread(this.Thread1Foo);  
 6     t1.Start(); //启动线程1  
 7     Thread t2 = new Thread(this.Thread2Foo);  
 8     t2.Start(); //启动线程2  
 9     Thread.Sleep(3000); //睡眠当前主线程,即调用BT_Temp_Click的线程  
10     _manualResetEvent.Set();   //想象成将IsRelease设为True   
11 }  
12     
13 void Thread1Foo()  
14 {  
15     _manualResetEvent.WaitOne();  
16     //阻塞线程1,直到主线程发信号给线程1,告知_menuResetEvent你的IsRelease属性已经为true,  
17     //这时不再阻塞线程1,程序继续往下跑  
18     MessageBox.Show("t1 end");  
19 }  
20     
21 void Thread2Foo()  
22 {  
23     _manualResetEvent.WaitOne();  
24     //阻塞线程2,直到主线程发信号给线程1,告知_menuResetEvent你的IsRelease属性已经为true,  
25     //这时不再阻塞线程2,程序继续往下跑  
26     MessageBox.Show("t2 end");  
27 }

注意这里ManualResetEvent和AutoResetEvent的一个重要区别:manual的话肯定会给线程1和线程2都发送一个信号,而auto只会随机给其中一个发送信号。这里引出了另一个问题——为什么一个叫manual而一个叫auto呢?我想这是很多人的疑问,现在我们就来解释这个问题。

刚才_manualResetEvent .Set();的这句话我想大家都明白了,可以看做将IsRelease的属性设置为true.线程1中 _manualResetEvent.WaitOne();接收到信号后不再阻塞线程1。在此之后的整个过程中IsRelease的值都是true.如果想将IsRelease的值回复成false,就必须再调用_manualResetEvent.Reset()的方法。如果是_autoResetEvent.set(),那么_autoResetEvent.WaitOne()后会自动将IsRelease的值自动设置为false.

我们再来说说Mutex对象,这个对象比较“专制”,同时段内只能准许一个线程工作。貌似通过给它取名的方式,还能控制多个进程的工作(这在我以前做的一个项目中验证过),可能相同名字的Mutex在操作系统中只能存在一个。

这三个类继承自同一个基类WaitHandle,这个基类有个方法令人困惑WaitOne(int millisecondsTimeout, bool exitContext),解释为Blocks the current thread until the current System.Threading.WaitHandle receives a signal, using a 32-bit signed integer to measure the time interval and specifying whether to exit the synchronization domain before the wait。难以理解的是最后一句:在等待前退出同步域。经过我艰苦不懈地研究发现了隐藏其中的奥秘(我只想说:干!)。社区论坛也有人跟我一样苦恼于此:autoEvent.WaitOne(1000,true)第二个参数啥作用啊,有高手知道吗?下面摘录高手回答。

假设有A线程和B线程,下面是相关代码:

 1 using System;     
 2 using System.Threading;       
 3         
 4 [System.Runtime.Remoting.Contexts.Synchronization(true)]   // 1     
 5 class My : ContextBoundObject     
 6 {    
 7      static void Main(string[] args)    
 8      {    
 9          My my = new My();     
10          ThreadPool.QueueUserWorkItem(my.FuncA);     
11          Thread.Sleep(50);    
12          ThreadPool.QueueUserWorkItem(my.FuncA);     
13          Thread.Sleep(50);    
14          ThreadPool.QueueUserWorkItem(my.FuncB);    
15          Thread.Sleep(50);    
16          ThreadPool.QueueUserWorkItem(my.FuncA);    
17            Console.ReadLine();    
18      }     
19     AutoResetEvent myEvent = new AutoResetEvent(false);          
20     public void FuncA(object state)      
21      {     
22          Console.WriteLine("Start A");      
23          System.Threading.Thread.Sleep(2000);      
24          Console.WriteLine("End   A");          
25     }          
26     public void FuncB(object state)          
27     {     
28          Console.WriteLine("Start B");     
29          myEvent.WaitOne(10 * 1000, true);                // 2     
30          Console.WriteLine("End   B");          
31     }    
32 }

在大部分情况下那个参数是没有用的。
只有在使用ContextBoundObject来进行同步的时候,那个参数才有用。
1、Synchronization可以用来同步一个类(基于ContextBoundObject)。
比如上面的例子,同一时间只能运行一个方法。把标志行1注释掉,则可观察到乱序执行。

2、WaitOne(...,true)使得方法B可以暂时脱离ContextBound同步保护,让A有机会在B等待的时候得到执行。比如以下的例子的结果为:
...
Start B
Start A
End   A
End   B 
把标志行2的true改成false,那么A就要等到B执行后才能执行。

转载请注明本文出处:http://www.cnblogs.com/newton/archive/2012/11/29/2793928.html 

目录
相关文章
|
存储 Python
用python将csv转excel (.xls和.xlsx)的几种方式
用python将csv转excel (.xls和.xlsx)的几种方式
670 4
|
Rust 安全 算法
【密码学】一文读懂BBS
之前聊过不少非密码学安全的伪随机数生成算法,这次呢,咱们来聊一个密码学安全的伪随机数生成器 「BBS」 ,这个是三位设计者的首字母: Blum、Blum 和 Shub。
【密码学】一文读懂BBS
|
安全 Java Android开发
Kotlin入门实用开发技巧与注意事项
本文源自公众号“AntDream”。Kotlin是由JetBrains开发的现代编程语言,自2017年成为Android官方开发语言后迅速流行。本文作者分享了Kotlin的实用技巧,包括变量声明、空安全、扩展函数等,帮助初学者避免常见问题。
152 15
|
11月前
|
传感器 机器学习/深度学习 自动驾驶
未来出行新纪元:自动驾驶技术深度剖析
【10月更文挑战第6天】 本文旨在深入探讨自动驾驶技术的工作原理、关键技术要素、当前主要挑战以及未来发展趋势。通过对感知、决策和执行层的细致分析,结合行业现状与前瞻,为读者提供一个关于自动驾驶技术的全面视角,揭示其如何引领交通运输领域迈向智能化、安全化与高效化的新阶段。
222 1
|
11月前
|
人工智能 自然语言处理 机器人
AI心语:智能时代的情感纽带
本文旨在探索人工智能在情感计算领域的应用,以及这些技术如何帮助我们更好地理解和模拟人类情感。通过分析当前的技术进展和面临的伦理挑战,文章为读者提供了一个关于AI与情感结合世界的全面视角。
875 6
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用问题之在自定义RichSinkFunction中,如何获取source的schema
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
Windows
Windows批处理(BAT)文件执行时“一闪而过或闪退”问题及解决方法
Windows批处理(BAT)文件执行时“一闪而过或闪退”问题及解决方法
5254 1
|
安全 Java 测试技术
【开题报告】基于SpringBoot的高校就业管理系统的设计与实现
【开题报告】基于SpringBoot的高校就业管理系统的设计与实现
779 0
|
资源调度 算法 Ubuntu
基于协方差矩阵自适应演化策略(CMA-ES)的高效特征选择
特征选择是指从原始特征集中选择一部分特征,以提高模型性能、减少计算开销或改善模型的解释性。特征选择的目标是找到对目标变量预测最具信息量的特征,同时减少不必要的特征。这有助于防止过拟合、提高模型的泛化能力,并且可以减少训练和推理的计算成本。
256 3
|
存储 NoSQL 关系型数据库
面试题14: 关系型数据库和非关系型数据库的区别
面试题14: 关系型数据库和非关系型数据库的区别
378 1