【转】多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(上)
本篇从Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler的类关系图开始,希望通过 本篇的介绍能对常见的线程同步方法有一个整体的认识,而对每种方式的使用细节,适用场合不会过多解释。让我们来看看这几个类的关系图:
1.lock关键字
lock是C#关键词,它将语句块标记为临界区,确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。方法是获取给定对象的互斥锁,执行语句,然后释放该锁。
MSDN上给出了使用lock时的注意事项通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则。
1)如果实例可以被公共访问,将出现 lock (this) 问题。
2)如果 MyType 可以被公共访问,将出现 lock (typeof (MyType))
问题由于一个类的所有实例都只有一个类型对象(该对象是typeof的返回结果),锁定它,就锁定了该对象的所有实例。微软现在建议不要使用
lock(typeof(MyType)),因为锁定类型对象是个很缓慢的过程,并且类中的其他线程、甚至在同一个应用程序域中运行的其他程序都可以访问
该类型对象,因此,它们就有可能代替您锁定类型对象,完全阻止您的执行,从而导致你自己的代码的挂起。
3)由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock(“myLock”) 问题。这个问题和.NET Framework创建字符串的机制有关系,如果两个string变量值都是"myLock",在内存中会指向同一字符串对象。
最佳做法是定义 private 对象来锁定, 或 private static对象变量来保护所有实例所共有的数据。
我们再来看看lock关键字的本质,lock关键字其实就是对Monitor类的Enter()和Exit()方法的封装,并通过
try...catch...finally语句块确保在lock语句块结束后执行Monitor.Exit()方法,释放互斥锁。
2.Monitor类
Monitor类通过向单个线程授予对象锁来控制对对象的访问。对象锁提供限制访问临界区的能力。当一个线程拥有对象的锁时,其他任何线程都不能获取该
锁。还可以使用 Monitor
来确保不会允许其他任何线程访问正在由锁的所有者执行的应用程序代码节,除非另一个线程正在使用其他的锁定对象执行该代码。
通过对lock关键字的分析我们知道,lock就是对Monitor的Enter和Exit的一个封装,而且使用起来更简洁,因此Monitor类的Enter()和Exit()方法的组合使用可以用lock关键字替代。
另外Monitor类还有几个常用的方法:
TryEnter()能够有效的解决长期死等的问题,如果在一个并发经常发生,而且持续时间长的环境中使用TryEnter,可以有效防止死锁或者长时间
的等待。比如我们可以设置一个等待时间bool gotLock =
Monitor.TryEnter(myobject,1000),让当前线程在等待1000秒后根据返回的bool值来决定是否继续下面的操作。
Wait()释放对象上的锁以便允许其他线程锁定和访问该对象。在其他线程访问对象时,调用线程将等待。脉冲信号用于通知等待线程有关对象状态的更改。
Pulse(),PulseAll()向一个或多个等待线程发送信号。该信号通知等待线程锁定对象的状态已更改,并且锁的所有者准备释放该锁。等待线程被
放置在对象的就绪队列中以便它可以最后接收对象锁。一旦线程拥有了锁,它就可以检查对象的新状态以查看是否达到所需状态。
注意:Pulse、PulseAll和Wait方法必须从同步的代码块内调用。
我们假定一种情景:妈妈做蛋糕,小孩有点馋,妈妈每做好一块就要吃掉,妈妈做好一块后,告诉小孩蛋糕已经做好了。下面的例子用Monitor类的Wait和Pulse方法模拟小孩吃蛋糕的情景。
- //仅仅是说明Wait和Pulse/PulseAll的例子
- //逻辑上并不严密,使用场景也并不一定合适
- class MonitorSample
- {
- private int n = 1; //生产者和消费者共同处理的数据
- private int max = 10000;
- private object monitor = new object();
- public void Produce()
- {
- lock (monitor)
- {
- for (; n <= max; n++)
- {
- Console.WriteLine("妈妈:第" + n.ToString() + "块蛋糕做好了");
- //Pulse方法不用调用是因为另一个线程中用的是Wait(object,int)方法
- //该方法使被阻止线程进入了同步对象的就绪队列
- //是否需要脉冲激活是Wait方法一个参数和两个参数的重要区别
- //Monitor.Pulse(monitor);
- //调用Wait方法释放对象上的锁并阻止该线程(线程状态为WaitSleepJoin)
- //该线程进入到同步对象的等待队列,直到其它线程调用Pulse使该线程进入到就绪队列中
- //线程进入到就绪队列中才有条件争夺同步对象的所有权
- //如果没有其它线程调用Pulse/PulseAll方法,该线程不可能被执行
- Monitor.Wait(monitor);
- }
- }
- }
- public void Consume()
- {
- lock (monitor)
- {
- while (true)
- {
- //通知等待队列中的线程锁定对象状态的更改,但不会释放锁
- //接收到Pulse脉冲后,线程从同步对象的等待队列移动到就绪队列中
- //注意:最终能获得锁的线程并不一定是得到Pulse脉冲的线程
- Monitor.Pulse(monitor);
- //释放对象上的锁并阻止当前线程,直到它重新获取该锁
- //如果指定的超时间隔已过,则线程进入就绪队列
- Monitor.Wait(monitor,1000);
- Console.WriteLine("孩子:开始吃第" + n.ToString() + "块蛋糕");
- }
- }
- }
- static void Main(string[] args)
- {
- MonitorSample obj = new MonitorSample();
- Thread tProduce = new Thread(new ThreadStart(obj.Produce));
- Thread tConsume = new Thread(new ThreadStart(obj.Consume));
- //Start threads.
- tProduce.Start();
- tConsume.Start();
- Console.ReadLine();
- }
- }
这个例子的目的是要理解Wait和Pulse如何保证线程同步的,同时要注意Wait(obeject)和Wait(object,int)方法
的区别,理解它们的区别很关键的一点是要理解同步的对象包含若干引用,其中包括对当前拥有锁的线程的引用、对就绪队列(包含准备获取锁的线程)的引用和对
等待队列(包含等待对象状态更改通知的线程)的引用。
【转】多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(上)的更多相关文章
- C#多线程:深入了解线程同步lock,Monitor,Mutex,同步事件和等待句柄(中)
本篇继续介绍WaitHandler类及其子类 Mutex,ManualResetEvent,AutoResetEvent的用法..NET中线程同步的方式多的让人看了眼花缭乱,究竟该怎么去理解呢?其实, ...
- C# 多线程(lock,Monitor,Mutex,同步事件和等待句柄)
本篇从 Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler 的类关系图开始,希望通过本篇的介绍能对常见的线程同步方法有一个整体的认识,而 ...
- 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock
[源码下载] 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLoc ...
- C#多线程同步事件及等待句柄AutoResetEvent 和 ManualResetEvent
最近捣鼓了一下多线程的同步问题,发现其实C#关于多线程同步事件处理还是很灵活,这里主要写一下,自己测试的一些代码,涉及到了AutoResetEvent 和 ManualResetEvent,当然还有也 ...
- C#各种同步方法 lock, Monitor,Mutex, Semaphore, Interlocked, ReaderWriterLock,AutoResetEvent, ManualResetEvent
看下组织结构: System.Object System.MarshalByRefObject System.Threading.WaitHandle System.Threading.Mutex S ...
- C#多线程之线程池篇1
在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...
- python类库32[多进程同步Lock+Semaphore+Event]
python类库32[多进程同步Lock+Semaphore+Event] 同步的方法基本与多线程相同. 1) Lock 当多个进程需要访问共享资源的时候,Lock可以用来避免访问的冲突. imp ...
- C#使用Monitor类、Lock和Mutex类进行多线程同步
在多线程中,为了使数据保持一致性必须要对数据或是访问数据的函数加锁,在数据库中这是很常见的,但是在程序中由于大部分都是单线程的程序,所以没有加锁的必要,但是在多线程中,为了保持数据的同步,一定要加锁, ...
- .NET多线程之线程安全,Lock(锁)、Monitor(同步访问)、LazyInitializer(延迟初始化)、Interlocked(原子操作)、static(静态)构造函数、volatile、
1.什么是线程安全 线程安全是编程中的术语,指某个函数.函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成.一般来说,线程安全的函数应该为每个调用它的线程分配专门的 ...
随机推荐
- 通过request获取网页资讯 通过BeautifulSoup剖析网页元素
import requests newsUrl ='http://news.sina.com.cn/china/' res = requests.get(newsUrl) res.encoding ...
- leetcode - [7]Binary Tree Preorder Traversal
Given a binary tree, return the preorder traversal of its nodes' values. For example:Given binary tr ...
- 20169207《Linux内核原理与分析》第九周作业
第九周的实验依旧和往常的一样,主要包括两部分.一是1.阅读学习教材「Linux内核设计与实现 (Linux Kernel Development)」第教材第13,14章.二是学习MOOC「Linux内 ...
- Java中sleep()与wait()区别(涉及类锁相关概念)
在区别之前,我们首先先了解一下关于对象锁,类锁的相关概念(当时查阅的详细地址:http://www.importnew.com/20444.html,该作者对类锁和对象锁进行了详细的举例分析) 对象锁 ...
- jvm调优的分类
本文部分内容出自https://blog.csdn.net/yang_net/article/details/5830820 调优步骤: 衡量系统现状. 设定调优目标. 寻找性能瓶颈. 性能调优. 衡 ...
- RxSwift学习笔记2:Observable/生命周期/Event/oneNext/onError/onCompleted/
Observable 是 Rx 的根基 官网:http://reactivex.io/ github地址:https://github.com/ReactiveX/RxSwift Observabl ...
- EBS中 EXCEL 格式报表输出的公用API
http://blog.itpub.net/10359218/viewspace-752601/ 最近的项目上写了一个公用的API,很久以前就用EXCEL发布过报表,但从没想过写API来简化... ...
- [控件]unigui移动端下Unidatepicker时间显示解决方案
[控件]unigui移动端下Unidatepicker时间显示解决方案 http://tz10000.com/kong-jian-unigui-yi-dong-duan-xia-unidatepick ...
- 源自KPI交谈的思考
说明白一件事情不容易 前言 跟领导谈及下半年KPI的时候,问我什么打算/计划,在交谈过程中,有几个有意思的点 问题 Q: 目标是hold住服务端,那么怎么样才算hold住服务端? Q: 如何推动别人去 ...
- SQLSERVER CXPACKET 等待
--SQLSERVER CXPACKET 等待 2013-6-11 2 --联机丛书: 3 --当尝试同步查询处理器交换迭代器时出现.如果针对该等待类型的争用成为问题时,可以考虑降低并行度 4 5 6 ...