同步方法调用异步方法导致无响应死锁的问题

在同步方法中,由于没有await ,直接调用Task.Result()或Task.Wait()时,会导致死锁

如:

DoAsync().Wait();

async Task DoAsync()
{
    await Task.Run(() => { });
}

必定会造成死锁,WCF,Webservice之类的,UI线程的

总结不会造成死锁的充分条件:

  1. 异步操作执行完后不需要回到原有线程(例如非 UI 线程和控制台线程);
  2. 异步操作不需要单独的线程执行任务。

为了防止真的有代码的调用者使用 Wait()、Result()

async Task DoAsync()
{
    await Task.Run(() => { }).ConfigureAwait(false);
}

这样,即便真的使用 DoAsync().Wait() 也不会发生死锁。注意,整个方法调用链都需要使用 .ConfigureAwait(false) 才能够防止线程切换时,在调用方的 Wait() 方法中发生死锁

指定了 ConfigureAwait(false),这意味着通知异步状态机 AsyncMethodStateMachine 并不需要使用设置好的 SynchronizationContext(对于 UI 线程,是 DispatcherSynchronizationContext)执行线程同步,而是使用默认的 SynchronizationContext,而默认行为是随便找个线程执行后面的代码。于是,await Task.Run 后面的代码便不需要返回原线程,也就不会发生死锁问题。

备注:如果是这种方式,则在异步方法的Task.ConfigureAwait(false)语句之后的代码块中,获取不了原始上下文的某些变量,容易造成NullReferenceException空值引用异常。

 

posted @ 2021-06-02 16:19  博客萌新  阅读(435)  评论(0编辑  收藏  举报