C# 锁与死锁

什么是死锁:

所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁。如下

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对象的锁定");
                }
            }
        }

通过Monitor的超时锁定机制避免死锁

直接使用Monitor类。其拥有TryEnter方法,该方法接受一个超时参数。如果在我们能够获取被lock保护的资源之前,超时参数过期,则该方法会返回 false.

/// <summary>
        /// 使用Monitor避免死锁
        /// </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对象失败,");
                }
            }
        }

if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5))) 这时候是尝试去获取lock1,

因为lock1倍分支线程给获取了,那么获取不到,这时候等待5秒,5秒后获取不到就直接走了lese这条路,然后就释放了lock2,这时候分支线程就继续运行。

原文地址:https://www.cnblogs.com/netlock/p/14061195.html