C# 多线程安全(4)lock的死锁问题2


勇哥注:

《多线程安全》这个系列会持续写下去,它是我的一个弱点,有兴趣的朋友可以选择性看看。


先看源码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Test();
        }

        static void LockTooMuch(object lock1, object lock2)
        {
            lock (lock1)  //锁定lock1对象
            {
                Thread.Sleep(1000); //线程挂起1s
                lock (lock2) //试图获取lock2对象的锁定
                {
                    Console.WriteLine("成功获取到lock2对象的锁定");
                }
            }
        }

        /// <summary>
        /// 造成一个死锁
        /// </summary>
        public static void Test()
        {
            //定义两个锁定对象
            object lock1 = new object();
            object lock2 = new object();

            //开启线程
            Thread t1 = new Thread(() => { LockTooMuch(lock1, lock2); });
            t1.Start();

            //在主线程中锁定lock2对象
            lock (lock2)
            {
                Console.WriteLine("这将要产生一个死锁");
                Thread.Sleep(1000);
                lock (lock1)  //试图访问lock1
                {
                    Console.WriteLine("成功获取到lock1对象的锁定");
                }
            }
        }

    }
}


这次死锁发生在Test()的lock(lock1)。

这个很容易理解,想使用lock1的引用时,但已经被LockTooMuch的lock(lock1)使用了这个引用。

而LockTooMuch想使用lcok2的引用,但已经被Test()引用了。

他们互相指望对方放弃引用。


下面谈谈解决办法:


改用Monitor.TryEnter方法进行锁,因为它提供超时机制。

程序执行效果如下:

image.png


        /// <summary>
        /// 避免死锁
        /// </summary>
        public static void Test2()
        {
            //定义两个锁定对象
            object lock1 = new object();
            object lock2 = new object();

            //开启线程
            Thread t1 = new Thread(() => { LockTooMuch(lock1, lock2); });
            t1.Start();

            //在主线程中使用Monitor类来锁定lock2对象
            //在主线程中锁定lock2对象
            lock (lock2)
            {
                Console.WriteLine("使用Monitor.TryEnter避免死锁,有一个超时时间的设定 超时返回false");
                Thread.Sleep(1000);
                //设置5s的超时时间
                if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5)))
                {
                    Console.WriteLine("成功获取到lock1对象的锁定");
                }
                else
                {
                    Console.WriteLine("获取lock1对象失败,");
                }
            }
        }


但是如果程序结构有问题,即使靠超时这种外力推一把,下个循环周期过来会不会还是会死锁呢?

这个也是我们需要考虑的问题。

但是至少这种超时机制做为一种检测是否有死锁问题出现的手段还是可以的。

如果程序自己都不知道自己死锁了,就只能看个屏幕发呆了。




--------------------- 

作者:hackpig

来源:www.skcircle.com

版权声明:本文为博主原创文章,转载请附上博文链接!


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864