如何在.NET 5控制台应用中复现异步死锁?
.NET 5 控制台应用异步死锁最小复现代码
默认.NET 控制台应用的同步上下文为null,await 完成后会直接在线程池线程上继续执行,因此默认不会触发ASP.NET/WinForms场景下的经典异步死锁。要复现对应死锁,需要先模拟单线程同步上下文,完整可运行代码如下:
using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; // 模拟UI/ASP.NET Classic的单线程同步上下文行为 class SingleThreadSynchronizationContext : SynchronizationContext { private readonly BlockingCollection<(SendOrPostCallback Callback, object State)> _taskQueue = new(); private readonly Thread _runThread = Thread.CurrentThread; public override void Post(SendOrPostCallback d, object state) => _taskQueue.Add((d, state)); public override void Send(SendOrPostCallback d, object state) { if (Thread.CurrentThread == _runThread) { d(state); return; } using var waitHandle = new ManualResetEventSlim(false); Post(_ => { d(state); waitHandle.Set(); }, null); waitHandle.Wait(); } public void StartProcessing() { foreach (var task in _taskQueue.GetConsumingEnumerable()) { task.Callback(task.State); } } public void StopProcessing() => _taskQueue.CompleteAdding(); } class Program { static async Task DemoAsync() { // await会捕获当前单线程同步上下文,等待完成后将剩余逻辑提交到上下文队列执行 await Task.Delay(100); } static void Main(string[] args) { // 为当前主线程设置自定义单线程同步上下文 var syncContext = new SingleThreadSynchronizationContext(); SynchronizationContext.SetSynchronizationContext(syncContext); try { // 异步方法同步等待,触发死锁 DemoAsync().Wait(); } finally { syncContext.StopProcessing(); } Console.WriteLine("程序执行完成(死锁状态下永远不会输出该行)"); } }
死锁原因说明
- 主线程调用
DemoAsync().Wait()后,会阻塞单线程同步上下文的唯一执行线程,等待DemoAsync任务执行完成 Task.Delay(100)计时结束后,需要把DemoAsync的剩余逻辑提交到单线程同步上下文的队列中等待执行- 同步上下文的唯一执行线程已经被
Wait()阻塞,无法处理队列中的任务,DemoAsync永远无法执行完成,形成永久死锁
内容的提问来源于stack exchange,提问作者Leonardo
相关产品推荐
相关产品推荐

