C#中使用try...finally处理代码不严谨时多线程出现的死锁

82 篇文章 3 订阅

当我们在处理多线程的同步锁时,如果不小心在某个条件下忘记释放锁。可能会造成死锁【DeadLock】等待。

可能出现死锁的方法,比如如下代码:

当输入参数在81~100时,将无法释放锁,导致下一次函数一直处于阻塞状态,无法继续执行

       static bool MayOccurDeadlock(string input, out string errMsg)
        {
            //添加锁
            while (Interlocked.Exchange(ref lockedValue, 1) != 0)
            {
                //此循环用于等待当前捕获current的线程执行结束
                Thread.SpinWait(20);
            }
            errMsg = "";
            int score;
            try
            {
                int.TryParse(input, out score);
                if (score > 100 || score < 0)
                {
                    errMsg = $"分数不能大于100,也不能为负数,当前分数:【{score}】";
                    throw new Exception(errMsg);
                }
                if (score > 80)
                {
                    errMsg = $"不考虑分数为优秀,当前分数:【{score}】";
                    return false;
                }
                int result = 80 / score;
                Console.WriteLine($"处理结果:【{result}】");
            }
            catch (Exception ex)
            {
                errMsg = $"筛选非优秀的分数操作出现错误:{ex.Message}";
                //释放锁
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return false;
            }
            //释放锁
            Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
            return true;
        }

解决方法:

在程序块try...catch后增加 finally统一释放锁对象。

确保锁最终一定要释放掉!

finally与return、throw关键字的优先级

finally优先级最高,return、throw优先级一致。即使try程序块中已经触发了return或者throw,仍然先执行finally,后续执行return操作

测试源程序如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HandleNotRigorousUseFinallyDemo
{
    class Program
    {
        /// <summary>
        /// 测试方法的委托
        /// </summary>
        /// <param name="input"></param>
        /// <param name="errMsg"></param>
        /// <returns></returns>
        delegate bool TestMethod(string input, out string errMsg);
        static void Main(string[] args)
        {
            Console.SetWindowSize(120, 30);
            string[] inputArray = new string[] { "120", "88", "33", "ABC" };
            TestLock(OptimizeLock, inputArray);
            Console.WriteLine("-----测试finally优化锁完成-----");
            TestLock(MayOccurDeadlock, inputArray);
            Console.WriteLine("-----测试死锁完成-----");
            Console.ReadLine();
        }

        /// <summary>
        /// 测试锁的方法
        /// </summary>
        /// <param name="testMethod"></param>
        /// <param name="inputArray"></param>
        static void TestLock(TestMethod testMethod, string[] inputArray)
        {
            List<Task> tasks = new List<Task>();
            Task task1 = Task.Run(() =>
            {
                string errMsg;
                bool result = testMethod(inputArray[0], out errMsg);
                Console.WriteLine($"【{inputArray[0]}】的处理结果:【{result}】,异常信息:【{errMsg}】");
            });
            tasks.Add(task1);
            Task task2 = Task.Run(() =>
            {
                string errMsg;
                bool result = testMethod(inputArray[1], out errMsg);
                Console.WriteLine($"【{inputArray[1]}】的处理结果:【{result}】,异常信息:【{errMsg}】");
            });
            tasks.Add(task2);

            Task task3 = Task.Run(() =>
            {
                string errMsg;
                bool result = testMethod(inputArray[2], out errMsg);
                Console.WriteLine($"【{inputArray[2]}】的处理结果:【{result}】,异常信息:【{errMsg}】");
            });
            tasks.Add(task3);

            Task task4 = Task.Run(() =>
            {
                string errMsg;
                bool result = testMethod(inputArray[3], out errMsg);
                Console.WriteLine($"【{inputArray[3]}】的处理结果:【{result}】,异常信息:【{errMsg}】");
            });
            tasks.Add(task4);
            Task.WaitAll(tasks.ToArray());
        }

        /// <summary>
        /// 用于排他锁,确保在多线程调用接口时,不会同时调用
        /// </summary>
        static int lockedValue = 0;

        /// <summary>
        /// 优化锁
        /// </summary>
        /// <param name="input"></param>
        /// <param name="errMsg"></param>
        /// <returns></returns>
        static bool OptimizeLock(string input, out string errMsg)
        {
            //添加锁
            while (Interlocked.Exchange(ref lockedValue, 1) != 0)
            {
                //此循环用于等待当前捕获current的线程执行结束
                Thread.SpinWait(20);
            }
            errMsg = "";
            int score;
            try
            {
                int.TryParse(input, out score);
                if (score > 100 || score < 0)
                {
                    errMsg = $"分数不能大于100,也不能为负数,当前分数:【{score}】";
                    throw new Exception(errMsg);
                }
                if (score > 80)
                {
                    errMsg = $"不考虑分数为优秀,当前分数:【{score}】";
                    return false;
                }
                int result = 80 / score;
                Console.WriteLine($"【{input}】处理结果:【{result}】");
                return true;
            }
            catch (Exception ex)
            {
                errMsg = $"筛选非优秀的分数操作出现错误:{ex.Message}";
                return false;
            }
            finally
            {
                //释放锁
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
            }
        }

        /// <summary>
        /// 可能会发生死锁的方法
        /// </summary>
        /// <param name="input"></param>
        /// <param name="errMsg"></param>
        /// <returns></returns>
        static bool MayOccurDeadlock(string input, out string errMsg)
        {
            //添加锁
            while (Interlocked.Exchange(ref lockedValue, 1) != 0)
            {
                //此循环用于等待当前捕获current的线程执行结束
                Thread.SpinWait(20);
            }
            errMsg = "";
            int score;
            try
            {
                int.TryParse(input, out score);
                if (score > 100 || score < 0)
                {
                    errMsg = $"分数不能大于100,也不能为负数,当前分数:【{score}】";
                    throw new Exception(errMsg);
                }
                if (score > 80)
                {
                    errMsg = $"不考虑分数为优秀,当前分数:【{score}】";
                    return false;
                }
                int result = 80 / score;
                Console.WriteLine($"处理结果:【{result}】");
            }
            catch (Exception ex)
            {
                errMsg = $"筛选非优秀的分数操作出现错误:{ex.Message}";
                //释放锁
                Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
                return false;
            }
            //释放锁
            Interlocked.Exchange(ref lockedValue, 0);//将current重置为0
            return true;
        }
    }
}

运行效果可能如图:

【死锁的将无法继续向下执行】

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯内科

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值