这篇文章将为大家详细讲解有关.NET监视程序中死锁怎么处理,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
监视程序主要是用来监控是否出现死锁等情况,但是这种.NET监视程序一般只能在测试中使用,如果大范围使用,很可能造成性能的下降。
每天回家路上总有一段比较长的路一片漆黑无法看书。这种时候,如果我有兴致则会用手机上上网,但是大部分情况下还是用来想问题的。刚才在路上想起今天的工作之一是让一个类型中的所有方法对多线程“完全互斥”——我不知道如何为它命名,我的意思是一个类中任意两个方法A或B,在A没有退出前,另一个线程是无法访问B的(当然也无法访问A)。最简单的方式应该是把每个方法标记为:
[MethodImpl(MethodImplOptions.Synchronized)] public void SomeMethod() { ... }
但是这意味着每进入一个方法,都会自动lock(方法所在的类型),锁定这样一个公开对象(甚至还是跨AppDomain的)自然不是一个好的做法。更好的做法是声明一个私有变量,然后对它进行lock。但是这意味着每个方法都需要用lock包含,我嫌麻烦,不知怎么又想尝试着使用一个公用的Lock方法,并传入一个Action对象,这样lock语句就只出现一次了:
private object m_mutex = new object(); private void Lock(Action action) { lock (this.m_mutex) action(); }
但是,这又意味着每个公开方法内部都要使用Lock方法,这和直接使用lock(this.m_mutex)又有什么区别呢?区别当然是有的,硬要说起来,使用Lock方法意味着“如果某一天”我要把“互斥”这个条件去掉的话,我只要修改Lock方法一个就可以了——否则我需要修改所有的公开方法。
当然,我觉得就这点理论上的“优势”是不足以修改代码的,那么我还是继续使用MethodImplOptions.Synchronized方式吧。
经过了上面这一圈没有带来多大价值的思考之后,我又回忆起今天园子首页的一篇文章谈到死锁。死锁很容易出现,例如下面的代码引发死锁的概率几乎是100%:
var mutexA = new object(); var mutexB = new object(); ThreadPool.QueueUserWorkItem((_) => { lock (mutexA) { Console.WriteLine("Mutex A acquired."); Thread.Sleep(1000); Console.WriteLine("Trying to acquire mutex B."); lock (mutexB) { Console.WriteLine("Mutex B acquired."); } } }); ThreadPool.QueueUserWorkItem((_) => { lock (mutexB) { Console.WriteLine("Mutex B acquired."); Thread.Sleep(1000); Console.WriteLine("Trying to acquire mutex A."); lock (mutexA) { Console.WriteLine("Mutex A acquired."); } } });
这种情况下两个内层lock中的代码都无法执行,因为每个线程都在等待对方释放才能继续下去,这种mutex锁定顺序不一致的情况导致死锁。那么概括下来,什么情况下会出现死锁呢?其实就是:“如果线程A正持有对象a而请求锁定b,同时线程B持有b而请求锁定c,同时线程C持有c而请求……锁定a”,无论这个循环有多长,其中涉及到多少个线程,一旦出现这种循环,则进入死锁。其实我想任何一本讲操作系统的书都会谈到到如何检查死锁——以及解开死锁。既然lock语句只能让我们静悄悄地等待下去,那么不如由我们自己提供一个实现,避免发生死锁的情况。例如:
public static class Lock { public static void With(object mutex, Action action) { ... } } 于是原本使用lock的语句现在就可以变成: //lock (mutex) //{ // ... //} Lock.With(mutex, () => { ... });
而在Lock.With方法中,我们除了调用Monitor.Enter/Exit方法来实现真正的锁之外,还需要在Enter之前判断这个mutex能否正确获得。其实就是查看一点:于此同时是否有另一个线程正持有当前mutex对象,并且(经过一个“链”)也在等待当前线程正持有的其他mutex对象。如果出现了这样的情况,则Lock.With不会调用Monitor.Enter,而是抛出异常。这样做肯定是可行的,问题的关键在于如何设计一个方便使用,性能优越,并且线程安全的数据结构。
关于“.NET监视程序中死锁怎么处理”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。