mutex互斥锁
NET多线程探索-互斥锁,信号量,事件(小新和拆弹部队友情演出)
2012-03-22 17:14 by 海不是蓝, 835 visits, 收藏 , 编辑
mutex互斥锁-不准确的时钟
概念性的东西:
互斥锁是一个互斥的同步对象,一个时间只有一个线程可以获取它。
前一篇文章中的时钟程序我们这里用Mutex互斥锁来实现。
class Program { static void Main( string [] args) { Clock C = new Clock (); C.RunClock(1); Console .Read(); } } public class Clock { public Mutex Mtx = new Mutex (); //开始运行时钟,输入运行分钟 public void RunClock( Int32 Minute) { Thread T1 = new Thread (( object Minute1) => { Int32 m = Convert .ToInt32(Minute1) * 60 / 2; while (m > 0) { DI( true ); m--; } }); Thread T2 = new Thread (( object Minute1) => { Int32 m = Convert .ToInt32(Minute1) * 60 / 2; while (m > 0) { DA( true ); m--; } }); T1.Start( true ); T2.Start( true ); } public void DI( bool run) { Mtx.WaitOne(); if (!run) { Mtx.ReleaseMutex(); return ; } else { Console .WriteLine( "嘀" ); Thread .Sleep(1000); Mtx.ReleaseMutex(); } } public void DA( bool run) { Mtx.WaitOne(); if (!run) { Mtx.ReleaseMutex(); return ; } else { Console .WriteLine( "嗒" ); Thread .Sleep(1000); Mtx.ReleaseMutex(); } } }
为什么会这样?貌似一切都是合理的!
这里我只发表下我的理解,还请个位园友自己认真分析下,毕竟我个人理解可能是错误的!
如果您发现我理解错了,请在评论指出,我好及时学习更早!
Monitor的时钟是使用了lock来锁定,lock最后也会被编译成为Monitor的Enter和Exit。
重点是Monitor在Pulse(obj)的时候已经就确定了另外一个等待obj被释放的线程拥有了执行权!
而Mutex在ReleaseMutex在释放锁定之后,当前线程和其他等待线程都执行WaitOne,导致了线程执行权的争夺!
随着程序的运行,线程之间的争夺激烈。
下面用互斥锁实现个例子,一个炸弹,同时只能一个人拆弹,如果超过1个人就爆炸。
class Program { static void Main( string [] args) { 炸弹 b = new 炸弹 (); b.拆弹(); b.拆弹(); Console .Read(); } } public class 炸弹 { private Int32 热度 = 0; public Mutex m = new Mutex (); public void 拆弹() { Thread t = new Thread (炸弹内部); t.Start(); } private void 炸弹内部() { m.WaitOne(); 热度++; Thread .Sleep(1000); if (热度>1) { Console .WriteLine( "炸弹爆炸!拆弹手见马克思..." ); m.ReleaseMutex(); return ; } 热度--; Console .WriteLine( "炸弹安全拆除!拆弹手这个月奖金加倍..." ); m.ReleaseMutex(); } }
拆弹手很幸运,这个月奖金加倍了。如果把Mutex去掉,那么马克思就等着他们去聊天。
互斥锁和同步都是锁定一个资源,同时只让一个线程去操作。
对于可以允许限定数量线程执行的情况互斥锁就不适合了,这里就需要信号量。
信号量通过一个计数器来控制对共享资源的访问,如果计数器的闲置数大于0,那么就允许访问,如果=0就拒绝访问。
public Semaphore( int initialCount, int maximumCount);
initialCount:可以同时授予的信号量的初始请求数。
maximumCount:可以同时授予的信号量的最大请求数。
public virtual bool WaitOne(); public int Release();
WaitOne():阻止当前线程,直到当前 System.Threading.WaitHandle 收到信号。
Release():退出信号量并返回前一个计数。
下面还是请出我们杯具的拆弹手来演示。
class Program { static void Main( string [] args) { //有关部门的砖家叫兽告诉拆弹手炸弹最多4个人同时拆 Int32 拆弹手人数 = 4; 炸弹 b = new 炸弹 (拆弹手人数); while (拆弹手人数 > 0) { b.拆弹(); 拆弹手人数--; } Console .Read(); } } public class 炸弹 { private Int32 最高温度 = 0; private Int32 热度 = 0; private Semaphore S; public 炸弹( Int32 limit) { 最高温度 = 3; S = new Semaphore (limit, limit); } public void 拆弹() { Thread t = new Thread (炸弹内部); t.Start(); } private void 炸弹内部() { S.WaitOne(); 热度++; Thread .Sleep(1000); if (热度 > 最高温度) { Console .WriteLine( "炸弹爆炸!拆弹手见马克思..." ); S.Release(); return ; } 热度--; Console .WriteLine( "炸弹安全拆除!拆弹手这个月奖金加倍..." ); S.Release(); } }
杯具的拆弹手,这里砖家叫兽错误指出最多4个人,而炸弹最高支持3个人!唉。。。
事件是另外一种同步对象,ManualResetEvent,AutoResetEvent2个类实现了事件同步的功能,都派生自EventWaitHandle类。
介绍下ManualResetEvent。
public ManualResetEvent( bool initialState); public virtual bool WaitOne(); public bool Reset(); public bool Set();
第一个是构造函数,传入的变量是事件是否发出信号。
第二个是等待一个事件发出信号,期间是阻塞的。
第三个是重置事件为未发出信号状态。
最后一个是设置事件为发出信号状态。
ManualResetEvent和AutoResetEvent的主要实现都是相同,只有一点不同,就是ManualResetEvent需要手动设置事件为未发出信号,而AutoResetEvent是自动设置的。
野原新之助的一天
class Program { static void Main( string [] args) { ManualResetEvent mal = new ManualResetEvent ( false ); 美女姐姐 美女 = new 美女姐姐 (); 小新 新之助 = new 小新 (); Thread t1 = new Thread ( new ParameterizedThreadStart (美女.美女姐姐上街)); Thread t2 = new Thread ( new ParameterizedThreadStart (新之助.小新出动)); t1.Start(mal); t2.Start(mal); Console .Read(); } public class 美女姐姐 { public void 美女姐姐上街( object Mal) { Thread .Sleep(2000); Console .WriteLine( "青春美丽的美女姐姐上街了..." ); Thread .Sleep(1000); (( ManualResetEvent )Mal).Set(); } } public class 小新 { public 小新() { Thread .Sleep(1000); Console .WriteLine( "小新拿着奶茶,猥琐的躲在大街边的绿化带里..." ); Thread .Sleep(1000); } public void 小新出动( object Mal) { ManualResetEvent Mal1 = ( ManualResetEvent )Mal; Console .WriteLine( "小新左右寻找美女姐姐..." ); //等待美女姐姐的出现 Mal1.WaitOne(); Console .WriteLine( "小新跑到美女姐姐面前,脱下小裤裤,亮出大象,开始跳大象舞..." ); Console .WriteLine( "屁股扭扭,“大象,大象,大象...”" ); Mal1.Reset(); } } }
不解释了。。。
写了这么多,应该好好思考下这些同步方式,每种虽然大概思路是一样!但是绝对有各自的特点。
有空大家还是看看CLR 3版中的线程核心部分,里面把这些同步的原理讲的很清楚。
总之线程的水太深,慢慢游吧,下一篇把剩下的一些线程同步方式讲下,然后就在最后对NET线程同步做个总结。
博客: hailan2012
邮箱:hailan2012@sina.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
随笔分类 -多线程编程
NET多线程探索-互斥锁,信号量,事件(小新和拆弹部队友情演出) 2012-03-22 17:14 by 海不是蓝, 835 visits, 网摘 , 收藏 , 编辑
4 Comment Categories: 多线程编程 Tags: 多线程 , 线程同步
NET多线程探索-线程同步和通信 2012-03-20 16:53 by 海不是蓝, 1157 visits, 网摘 , 收藏 , 编辑
5 Comment Categories: 多线程编程 Tags: 多线程 , 同步 , 线程通信
NET多线程探索-NET线程基础知识点 2012-03-19 13:40 by 海不是蓝, 216 visits, 网摘 , 收藏 , 编辑
0 Comment Categories: .NET Framework , 多线程编程 Tags: 多线程
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息