WinForm中的一种死锁场景
2018-06-17 21:03:44来源:未知 阅读 ()
最近客户反映系统总是时不时的卡死一次,开始以为是电脑环境问题,后来发现其他电脑上也会出现这种问题。收到反馈后,就开始找原因呀 ,重现呀。折腾了一上午终于找到了原因:“死锁”;
这个死锁发生的有点奇怪。因为只有一个同步根,怎么也会死锁呢。下面写一段小代码 描述一下发生死锁的情形:
1: using System;
2: using System.Collections.Generic;
3: using System.ComponentModel;
4: using System.Data;
5: using System.Drawing;
6: using System.Linq;
7: using System.Text;
8: using System.Windows.Forms;
9: using System.Threading;
10:
11: namespace DeadLock
12: {
13: public partial class Form1 : Form
14: {
15: Button btnGetValue;
16: public Form1()
17: {
18: InitializeComponent();
19: this.Controls.Add(btnGetValue);
20: btnGetValue.Click += new EventHandler(btnGetValue_Click);
21: DataPoolManager.GetInstance().ValueChanged += new DataPoolManager.ValueChangedHandle(Form1_ValueChanged);
22: }
23:
24: void btnGetValue_Click(object sender, EventArgs e)
25: {
26: int index = 0;
27: string colName = string.Empty;
28: //do something....
29: DataPoolManager.GetInstance().GetValue(index, colName);
30: }
31:
32: void Form1_ValueChanged(object sender, EventArgs e)
33: {
34: //do something...
35: Thread.Sleep(100);
36: //造成死锁的位置
37: this.Invoke((MethodInvoker)delegate()
38: {
39: //do something
40: });
41: }
42: }
43:
44: public class DataPoolManager
45: {
46: private DataPoolManager() { }
47:
48: static DataPoolManager instance;
49:
50: public static DataPoolManager GetInstance()
51: {
52: if (instance == null)
53: {
54: lock (syncRoot)
55: {
56: if (instance == null)
57: {
58: instance = new DataPoolManager();
59: }
60: }
61: }
62: return instance;
63: }
64:
65: /// <summary>
66: /// 同步根
67: /// </summary>
68: static readonly object syncRoot = new object();
69:
70: public delegate void ValueChangedHandle(object sender,EventArgs e);
71:
72: /// <summary>
73: /// 肇事事件 ,该事件被UI窗体注册
74: /// </summary>
75: public event ValueChangedHandle ValueChanged;
76:
77: /// <summary>
78: /// 这个方法可能被UI线程调用
79: /// </summary>
80: public string GetValue(int rowIndex, string colName)
81: {
82: //造成死锁的位置
83: lock (syncRoot)
84: {
85: //do something...
86: Thread.Sleep(100);
87: return DateTime.Now.ToString("yyyy-MM-dd HH:MM ss");
88: }
89: }
90:
91: /// <summary>
92: /// 这个方法由线程池中的某个线程调用,是个比较耗时的操作
93: /// </summary>
94: public bool SetValue(string key, string colName, string newValue)
95: {
96: bool result = false;
97: lock (syncRoot)
98: {
99: // do something...
100: Thread.Sleep(100);
101: if (result == true)
102: {
103: //引发肇事事件
104: OnValueChanged(new EventArgs());
105: }
106: }
107: return result;
108: }
109:
110: private void OnValueChanged(EventArgs eventArgs)
111: {
112: ValueChangedHandle handle = ValueChanged;
113: if (handle != null)
114: {
115: handle(this, eventArgs);
116: }
117: }
118:
119: }
120: }
在窗体上注册了 DataPoolManager 的 ValueChanged 事件 ,该事件不是由UI线程引发的,所以在事件处理中 使用了 this.Invoke 方法 ,见代码第37行。这本没什么错误,但是关键在于 这个事件是在 DataPoolManager 对象中 SetValue 方法中的 Lock 语句块中引发的 。这就意味着如果该事件不执行完,同步根将一直被“占用”。这时候 ,在SetValue方法没有引发事件之前 ,如果UI线程调用了 GetValue 方法 ,UI线程将在代码的 第 83 行出等待 ,而 执行 SetValue的方法引发事件后,在 代码 37 行出 执行 this.Invoke 的时候 发生死锁。
找到原因了,问题就好解决了,有两个解决方案:
1,SetValue 方法中,引发事件的操作放到Lock块的外部执行。如下:
1: public bool SetValue(string key, string colName, string newValue)
2: {
3: bool result = false;
4: lock (syncRoot)
5: {
6: // do something...
7: Thread.Sleep(100);
8: }
9: if (result == true)
10: {
11: //在同步块外部引发事件
12: OnValueChanged(new EventArgs());
13: }
14: return result;
15: }
2,将事件处理中的this.Invoke 改成 this.BeginInvoke:
1: void Form1_ValueChanged(object sender, EventArgs e)
2: {
3: //do something...
4: Thread.Sleep(100);
5: //不等待返回
6: this.BeginInvoke((MethodInvoker)delegate()
7: {
8: //do something
9: });
10: }
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:委托与事件的关系
- .NET中的计时器控件Timer 2018-06-21
- .NET中的访问修饰符 2018-06-21
- 委托 与 事件 2018-06-21
- C# 字符串的入门 2018-06-21
- 获取checkboxlist选中的值以及绑定来自之前选中的来自数据库 2018-06-17
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash