Jeffrey Richter在《Windows核心编程(第5版)》中描述了一个死锁情况:假设线程Thread1和Thread2均需要独占方式访问互斥资源m_res1、m_res2,应用互斥对象Monitor在使用前Enter(相当于加锁)、使用后Exit(相当于解锁)。由于涉及到两个资源,此时需要特别注意加锁的顺序。如果两个线程的加锁顺序不同(Thread1先锁m_res2、Thread2先锁m_res1),此时容易发生死锁。依据该思路,下面给出了C#实现的完整程序代码:
class Program{ private static object m_res1 = new object(); private static object m_res2 = new object(); private static int m_count = 0; static void Main(string[] args) { Thread t1 = new Thread(Thread1); Thread t2 = new Thread(Thread2); t1.Start(); t2.Start(); while (true) { int preCount = m_count; Thread.Sleep(0); // 放弃当前线程的CPU时间片,Windows可能调度其他线程 if (preCount == m_count) // 数据没有变化,表明线程没有执行 { Console.WriteLine("dead lock! count: {0}", m_count); } } } private static void Thread1() { while (true) { Monitor.Enter(m_res2); // 先锁 m_res2 Monitor.Enter(m_res1); // 再锁 m_res1 m_count++; Monitor.Exit(m_res1); // 释放锁不存在先后关系 Monitor.Exit(m_res2); } } private static void Thread2() { while (true) { Monitor.Enter(m_res1); // 先锁 m_res1 Monitor.Enter(m_res2); m_count++; Monitor.Exit(m_res1); Monitor.Exit(m_res2); } }}
运行上述程序时,一般计数到300左右(笔者的机器)就发生死锁现象了。其原因为:如果Thread1锁住m_res2同时、Thread1获得m_res1的锁,那么Thread1就不能获得m_res1的锁,当然Thread2也不能获得m_res2的锁。这两个线程都不能继续下去,于是m_count的值没有变化。
如果线程Thread1的加锁顺序与线程Thread2相同,即:
Monitor.Enter(m_res1);
Monitor.Enter(m_res2);
此时,将不会出现死锁情况。假设Thread1锁住m_res1且申请锁m_res2,Thread2锁住m_res2并申请m_res1,可以证明不会出现这种情况:因为Thread2锁住m_res2时要么是先锁住了m_res1,要么是释放m_res1时来不及释放m_res2。第一种现象不可能,因为Thread1锁住了m_res1;第二种现象是释放锁,不存在马上申请锁。所以,顺序相同时不会出现死锁情况。
解决的方法还有:使用bool Monitor.TryEnter()方法,尝试加锁并设定一个时间上界。如果锁不住,则放弃加锁,做其他操作。
总结:在多线程对多个资源加锁时,一定要按相同的顺序。
文章来源:http://www.evget.com/zh-CN/Info/ReadInfo.aspx?id=9084
分享到:
相关推荐
本文档是使用C#编写的银行家算法避免死锁的程序设计。里面包含数组初始化,利用递归判断输入整数,输出安全序列等函数,希望对大家有帮助。如有错误,请多多指教~
本次课程设计的内容是采用银行家算法,编写和调试一个仿真模拟银行家算法避免死锁的程序。设计5个并发进程共享3类不同的系统资源,即A类资源、B类资源、C类资源和可用资源数量A类资源、B类资源、C类资源。系统进行...
本次课程设计通过编写和调试一个仿真模拟银行家算法避免死锁的程序,观察产生死锁的条件,并采用银行家算法,有效地避免死锁的发生。这是我们的操作系统课程设,用.net做的。 银行家算法避免死锁,其中有三个模块,...
(1)请设计一个程序演示死锁避免算法(银行家算法)。 (2)要求该演示程序可以指定任意的进程数量、资源种类、每种资源总数量(大于等于1)、已分配数量、最大需求数量,同时也可以随机生成上述数值进行模拟(随机...
监控进程状态,无界面、托盘图标。
很好用,很容易看明白,通过编写和调试一个系统动态分配资源的简单模拟程序,观察死锁产生的条件,并采用适当的算法,有效地防止和避免死锁地发生。
这是操作系统中一个避免死锁的经典算法,为c#改写
主要介绍了C#中lock死锁的用法,对于共享资源的访问及C#程序设计的安全性而言,有着非常重要的意义!需要的朋友可以参考下
可能发生死锁的程序类型 1、WPF/WinForm程序 2、asp.net (不包括asp.net core)程序 死锁的产生原理 对异步方法返回的Task调用Wait()或访问Result属性时,可能会产生死锁。 下面的WPF代码会出现死锁: private void ...
一个很不错的C#录音控件源码,如果觉得超值请好评。谢谢! 以下文字是帮您提供提示出错的解决方案 在用VS2005中编写一个非常简单的播放器程序时编译是OK的。当我Debug运行的时候遇到了问题,现象如下: LoaderLock ...
实例60 一个有趣的DOS实用程序 实例61 代表元基本应用 实例62 有趣的事件代表元 实例63 随机连续偶数发生事件处理 实例64 有趣的列表框窗体 实例65 数学函数应用 第3篇 Visual C#高级编程实例 实例66 文件夹...
2. 用一个输入变量控制是否有左撇子哲学家。如果有,其数量由随机数生成。 3. 模拟程序分为两种情况, (1) 可能发生死锁的情况,输出发生死锁时的资源分配状态和历史资源分配状态; (2) 设计没有死锁发生的程序...
012.C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子。.doc 013.C#_.net环境下与单片机串行通信的实践.doc 014.单片机控制8路舵机程序+串口通讯上位机程序(C_带图).doc 015.基于C_实现PC机与A
由这个简单的例子可以看出,发生死锁需要四个必要条件,如下:主体对于资源是独占的,图1中每条汽车道只能跑一队汽车,不能跑第二队。指主体已经保持至少一个资源,但又提出了新的资源请求,而该
网上的很多相关的串口的源码是有问题的,至少有很多的bug,特别是死锁的问题大部分都没有解决,如果你也正好遇到这个问题,或许可以帮你解决燃眉之急,当然程序难免有些小错误,欢迎提出,谢谢。
最近在做一个有关高铁模拟仓显示系统的客户端程序,在这个程序中要运用串口serialPort传输数据,因为每次接收数据结束后要更新UI界面,所以就用到了的Invoke,将更新UI的程序代码封装到一个方法中,然后通过Incoke...
” 实例7 组件化“Welcome”程序 实例8 网络上的“Hello World” 实例9 Ref、Out与Params描述符的应用 实例10 C#自动内存管理的应用 实例11 一个有趣栈类的实现 实例12 垃圾收集器管理与...
创建一个简单的Windows窗体 328 创建Windows Forms程序 332 XML文档型注释 357 第14章 用ADO.NET访问数据 360 关系型数据库与SQL 360 ADO.NET对象模型 364 开始使用ADO.NET 366 使用OLE DB托管提供程序 369 使用数据...
” 实例7 组件化“Welcome”程序 实例8 网络上的“Hello World” 实例9 Ref、Out与Params描述符的应用 实例10 C#自动内存管理的应用 实例11 一个有趣栈类的实现 实例12 垃圾收集器管理与...
创建一个简单的Windows窗体 328 创建Windows Forms程序 332 XML文档型注释 357 第14章 用ADO.NET访问数据 360 关系型数据库与SQL 360 ADO.NET对象模型 364 开始使用ADO.NET 366 使用OLE DB托管提供程序 369 使用数据...