C#的两种常见的死锁情况

工作中遇到的两种线程锁死的情况,特此记录:

1.Thread1和Thread2抢占同一对象中的2个锁obj1和obj2,对象如下:

 1 public class Test
 2 {
 3     object _obj1;
 4     object _obj2;
 5     public Test()
 6     {
 7         _obj1 = new object();
 8         _obj2 = new object();
 9     }
10     public void Test1(string name)//线程1调用
11     {
12         lock (_obj1)
13         {
14             Console.WriteLine(name + " Lock Obj1");
15             lock (_obj2)
16             {
17                 Console.WriteLine(name + " Lock Obj2");
18             }
19             Console.WriteLine(name + " Release Obj2");
20         }
21         Console.WriteLine(name + " Release Obj1");
22     }
23     public void Test2(string name)//线程2调用
24     {
25         lock (_obj2)
26         {
27             Console.WriteLine(name + " Lock Obj2");
28             lock (_obj1)
29             {
30                 Console.WriteLine(name + " Lock Obj1");
31             }
32             Console.WriteLine(name + " Release Obj1");
33         }
34         Console.WriteLine(name + " Release Obj2");
35     }
36 }
View Code

调用方式如下:

 1 static void Main(string[] args)
 2 {
 3     Test p = new Test();
 4     Thread th = new Thread(() =>
 5     {
 6         while (true)
 7         {
 8             p.Test1(Thread.CurrentThread.ManagedThreadId.ToString());
 9         }
10     });
11     th.Start();
12     th = new Thread(() =>
13     {
14         while (true)
15         {
16             p.Test2(Thread.CurrentThread.ManagedThreadId.ToString());
17         }
18     });
19     th.Start();
20 }
View Code

此种情况导致Thread1占用obj1等待obj2,Thread2占用obj2等待obj1,两个线程均阻塞导致死锁情况发生。执行最终如下:

解决方案:1.编程中不要使用这种嵌套写法;2.使用Monitor.TryEnter()方法。

2.Winform主线程抢占对象中的锁obj1,对象子线程占用obj1使用invoke方法调用,对象类如下:

 1 public class Test
 2 {
 3     string str;
 4     Form1 form;
 5     object _obj1;
 6     public Test(Form1 f)
 7     {
 8         this.form = f;
 9         _obj1 = new object();
10         Thread th = new Thread(Monitor);
11         th.IsBackground = true;
12         th.Start();
13     }
14     void Monitor()//将字符串显示在UI界面
15     {
16         while (true)
17         {
18             Thread.Sleep(50);
19             lock (_obj1)
20             {
21                 form.Show(str);
22             }
23         }
24     }
25     public void Test1()//UI调用,修改字符串的值
26     {
27         lock (_obj1)
28         {
29             str = DateTime.Now.ToString("HH:mm:ss:fff");
30         }
31     }
32 }
View Code

Winform代码如下:

 1 Test t;
 2 public Form1()
 3 {
 4     InitializeComponent();
 5     t = new Test(this);
 6 }
 7 public void Show(string txt)//子线程占用锁时来操作控件
 8 {
 9     if (this.InvokeRequired)
10         this.Invoke(new Action<string>(Show), txt);
11     else
12         this.label1.Text = txt;
13 }
14 private void timer1_Tick(object sender, EventArgs e)
15 {
16     t.Test1();//定时器不停地调用
17 }
View Code

启动后可看到程序会卡死,字符串不再刷新。

 解决方案:使用BeginInvoke方法替换Invoke;

 

posted @ 2023-06-06 11:29  [春风十里]  阅读(205)  评论(0编辑  收藏  举报