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

当我们在处理多线程的同步锁时,如果不小心在某个条件下忘记释放锁。可能会造成死锁【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;
        }
    }
}

运行效果可能如图:

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

 

おすすめ

転載: blog.csdn.net/ylq1045/article/details/120251615