马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
死锁的示例
下面就是一个会死锁的示例代码:- // 异步死锁示例 - 不使用 TaskScheduler,仅用多个 Task 互相等待
- Console.WriteLine("=== 多 Task 互相等待死锁 ===\n");
- // 两个任务互相用 .Result 等待对方完成 → 死锁
- var tcsA = new TaskCompletionSource<int>();
- var tcsB = new TaskCompletionSource<int>();
- var taskA = Task.Run(() =>
- {
- Console.WriteLine($"[任务 A] 开始,线程 {Environment.CurrentManagedThreadId}");
- Console.WriteLine("[任务 A] 等待任务 B 的结果...");
- int resultB = tcsB.Task.Result; // A 阻塞等待 B
- Console.WriteLine($"[任务 A] 收到 B 的结果: {resultB}");
- tcsA.SetResult(1);
- });
- var taskB = Task.Run(() =>
- {
- Console.WriteLine($"[任务 B] 开始,线程 {Environment.CurrentManagedThreadId}");
- Console.WriteLine("[任务 B] 等待任务 A 的结果...");
- int resultA = tcsA.Task.Result; // B 阻塞等待 A
- Console.WriteLine($"[任务 B] 收到 A 的结果: {resultA}");
- tcsB.SetResult(2);
- });
- Console.WriteLine("等待所有任务完成(将在此处挂起)...\n");
- Console.WriteLine("死锁原因:");
- Console.WriteLine("- 任务 A 用 .Result 阻塞等待 tcsB.Task 完成");
- Console.WriteLine("- 任务 B 用 .Result 阻塞等待 tcsA.Task 完成");
- Console.WriteLine("- tcsA.SetResult() 要等 A 等到 B 之后才会执行");
- Console.WriteLine("- tcsB.SetResult() 要等 B 等到 A 之后才会执行");
- Console.WriteLine("- A 等 B,B 等 A → 死锁\n");
- Task.WaitAll(taskA, taskB);
- Console.WriteLine("若看到这行说明未发生死锁(本示例中应看不到)");
复制代码 任务 A: 壅闭在 tcsB.Task.Result → 等 B 完成
任务 B: 壅闭在 tcsA.Task.Result → 等 A 完成
↑_______________________________↓
- A 要比及 tcsB.SetResult(2) 被调用才会从 .Result 返回
- B 要比及 tcsA.SetResult(1) 被调用才会从 .Result 返回
- 而 tcsA.SetResult(1) 在 A 里、tcsB.SetResult(2) 在 B 里,都要等对方先返回
- 以是谁都不会先完成 → 死锁
办理办法
这个代码运行起来肯定会死锁,固然实际项目中死锁的发生比这个要复杂,但是原理相似。
办理办法就是把.Result如许的壅闭写法改成async await方式。
线程池饥饿
实际中大概是并发太高,线程池饥饿导致死锁,也就是:线程池里的工作线程数目有限。当大量任务都在壅闭等候(比方 .Result、.Wait()、Thread.Sleep()、lock 等)时,这些线程被占满且不会很快开释,新提交的任务只能在队列里等线程,就形成线程池饥饿:有活要干,但没有空闲线程来干。
免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金. |