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

勇哥注:

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


下面源码运行后会发生死锁。


image.png



源码:

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)
        {
            classA ca = new classA();
            classB cb = new classB();
            ca.show(cb);
            cb.show(ca);
        }
    }


    public class classA
    {
        //注意这里是public
        public static readonly object lockobj = new object();
        public void show(object lockobj)
        {
            for (int i = 0; i < 5; i++)
            {
                int k = i;
                Task.Run(() =>
                {
                    lock (this)
                    {
                            Console.WriteLine("ca...");
                        lock(lockobj)
                        {
                            Console.WriteLine($"{i},{k},classAstart...[{Thread.CurrentThread.ManagedThreadId}]");
                            Thread.Sleep(1000);
                            Console.WriteLine($"{i},{k},classAend...[{Thread.CurrentThread.ManagedThreadId}]");
                        }
                    }
                });
            }
        }
    }

    public class classB
    {
        //注意这里是public
        public static readonly object lockobj = new object();
        public void show(object lockobj)
        {
            for (int i = 0; i < 5; i++)
            {
                int k = i;
                Task.Run(() =>
                {
                    lock (this)
                    {
                            Console.WriteLine("cb...");
                        lock (lockobj)
                        {
                            Console.WriteLine($"{i},{k},classBstart...[{Thread.CurrentThread.ManagedThreadId}]");
                            Thread.Sleep(1000);
                            Console.WriteLine($"{i},{k},classBend...[{Thread.CurrentThread.ManagedThreadId}]");
                        }
                    }
                });
            }
        }
    }
}


classA中锁住了ca的引用(this就是ca),再锁住cb的引用。

classB中锁住了cb的引用,再锁住了ca的引用。

由于ca.show(cb)先执行,所以先lock(this),这个可以过,因为ca这时候没人引用,然后再lock(lockobj),它传入的是cb,而此时cb也无人引用,所以可以过。 

打印信息,其中延时了1000ms。

注意这个时候cb.show(ca)早已经开始执行了。它的lock(this) 要等到classA的两条信息打印完毕,释放了对cb的引用,进去。但是无法继续进入下一个lock(lockobj), 因为classA的第2 个循环已经进入了lock(this),占用了对ca的引用。


再对比一下执行结果,验证一下勇哥所讲。

image.png



引用一些资料:


什么是死锁?


线程死锁是指由于两个或者多个线程互相持有对方所需要的资源会互相等待对方释放资源,导致这些线程处于等待状态,无法前往执行。如果线程都不主动释放所占有的资源,将产生死锁。

当然死锁的产生是必须要满足一些特定条件的:

1.互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放

2.请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。

3.不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用

4.循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。



按上面说法,本例子死锁是因为1(互斥条件)


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

作者:hackpig

来源:www.skcircle.com

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


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

发表评论:

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

会员中心
搜索
«    2025年4月    »
123456
78910111213
14151617181920
21222324252627
282930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 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