当我们在处理多线程的同步锁时,如果不小心在某个条件下忘记释放锁。可能会造成死锁【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;
}
}
}
运行效果可能如图:
【死锁的将无法继续向下执行】