在某个项目开发过程中,偶然间发现在UI线程中async,await,wait三者一起使用会引发一个必然性的死锁问题。

一个简单的实例,代码很简单,在界面上放置一个Button,并在Button的click事件中调用一个Async标记的异步线程Run并调用Task 的Wait方法,注意Run方法开启的线程中什么代码都没有执行,然而这个时候运行程序并点击Button按钮会直接导致界面假死,这是由于Run方法中开启的线程和主线程产生死锁导致。

   

我们可以分析下点击Button按钮之后代码的执行顺序:

1.触发Button_Click事件之后,会调用Run方法,主线程会开始执行Run方法中的代码。

2.在Run方法中主线程执行到await关键字,会兵分两路,主线程跳出Run方法并执行Wait方法,并开始等待Run方法中的线程执行完成,而await后面的Task中的代码会继续执行。

3.然而由于await关键字的机制,在UI线程中调用await关键字后,Task.Run后面的代码同步交给UI线程去执行,即使后面没有代码需要执行。然而这个时候的UI线程正在等待Run中的线程执行完成,这就造成了一个非常典型的死锁问题。

可以标记下代码的执行顺序:

同样的,当run方法返回的是带有返回值的线程,并且在UI线程中通过Result获取值,也会产生同样的死锁问题。

当然,在UI线程中为了保持UI的响应性,一般也很少会使用wait关键字来等待一个线程。只不过当你在开发一个类库给项目中的其他人员使用的时候,为了避免使用者使用不当,还是 建议在线程之后加上ConfigureAwait(false),将其配置为在UI线程不可等待。

 await Task.Run(()=> {

            }).ConfigureAwait(false);

以上问题是在UI线程中产生的,那如果是在非UI线程中执行以上代码也会产生死锁么?答案是不会。

这是因为在非UI线程中,第四步的代码会从线程池中抓取空闲线程执行,而await的调用线程不可能是空闲线程,所以就不会产生于类似的死锁问题。

不过,无论是在UI线程还是非UI线程,都不建议把wait和await 、async混合使用。

一旦在代码中使用了await 、async,最好一直使用,一定要避免使用Task.WaitTask<T>.Result方法。

wait 和async,await一起使用引发的死锁问题的更多相关文章

  1. [.NET] 利用 async & await 的异步编程

    利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html  目录 异步编程的简介 异 ...

  2. Python PEP 492 中文翻译——协程与async/await语法

    原文标题:PEP 0492 -- Coroutines with async and await syntax 原文链接:https://www.python.org/dev/peps/pep-049 ...

  3. [译]async/await中阻塞死锁

    这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Cleary的两篇博文中翻译过来. 原文1:Don'tBlock o ...

  4. 传统asp.net小心 async/await坑

    最近在改老项目时,干了一件自以为很有成就感的事,心想 “项目都是同步方法,为啥不用异步方法呢?”,于是有了异步方法,类型下面的代码(当然是举例子说明啊) //更新某人名下公司名称 public Tas ...

  5. 异步编程(async&await)

    前言 本来这篇文章上个月就该发布了,但是因为忙 QuarkDoc 一直没有时间整理,所以耽搁到今天,现在回归正轨. C# 5.0 虽然只引入了2个新关键词:async和await.然而它大大简化了异步 ...

  6. .NET 基于任务的异步模式(Task-based Asynchronous Pattern,TAP) async await

    本文内容 概述 编写异步方法 异步程序中的控制流 API 异步方法 线程 异步和等待 返回类型和参数 参考资料 下载 Demo 下载 Demo TPL 与 APM 和 EAP 结合(APM 和 EAP ...

  7. MVC+Spring.NET+NHibernate .NET SSH框架整合 C# 委托异步 和 async /await 两种实现的异步 如何消除点击按钮时周围出现的白线? Linq中 AsQueryable(), AsEnumerable()和ToList()的区别和用法

    MVC+Spring.NET+NHibernate .NET SSH框架整合   在JAVA中,SSH框架可谓是无人不晓,就和.NET中的MVC框架一样普及.作为一个初学者,可以感受到.NET出了MV ...

  8. 【转】C# Async/Await 异步编程中的最佳做法

    Async/Await 异步编程中的最佳做法 Stephen Cleary 近日来,涌现了许多关于 Microsoft .NET Framework 4.5 中新增了对 async 和 await 支 ...

  9. 现代JS中的流程控制:详解Callbacks 、Promises 、Async/Await

    JavaScript经常声称是_异步_.那是什么意思?它如何影响发展?近年来这种方法有何变化? 请思考以下代码: result1 = doSomething1(); result2 = doSomet ...

随机推荐

  1. 抽象的(abstract)方法是否可同时是静态的(static), 是否可同时是本地方法(native),是否可同时被 synchronized 修饰?

    都不能.抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛 盾的.本地方法是由本地代码(如 C 代码)实现的方法,而抽象方法是没有实现 的,也是矛盾的.synchronized 和方法的实 ...

  2. 学习GlusterFS(六)

    一.GlusterFS概述 分布式文件系统由来 在介绍之前我们先来看下文件系统及典型的NFS文件系统. 计算机通过文件系统管理,存储数据的.而现在数据信息时代中人们可获取数据成指数倍的增长,单纯通过增 ...

  3. Heartbeat+DRBD+NFS

    添加路由心跳线 master: # route add -host 10.20.23.111 dev eth2 # echo "/sbin/route add -host 10.20.23. ...

  4. 自制jq分页插件

    由于第一次写jq插件,中间有借鉴别人的代码. (function(){ var ms = { fillHtml: function(obj, option) { obj.empty(); var to ...

  5. mapreduce统计单词

    源代码: WordCountMapper.java: package cn.idcast.mapreduce; import org.apache.hadoop.io.LongWritable; im ...

  6. Hadoop本地编写的jar包放到集群执行时报错处理

    错误描述: 020-03-24 22:45:23,204 WARN org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor ...

  7. C语言-操作符与表达式

    C语言入门之操作符与表达式 前言 本篇文章主要包括各种操作符的介绍与表达式求值,欢迎各位小伙伴与我一起学习. 一.操作符 分类 算术操作符 移位操作符 位操作符 赋值操作符 单目运算符 关系操作符 逻 ...

  8. 2021年iOS 开发者账号申请-最新

    前言 现在已经是2021年了,中国国内的互联网生态国家管控越来越严禁,国家反垄断法,未成年人游戏限制,整治娱乐圈不良文化,出台公民网络个人信息保护法,全网进行app 应用进行安全审查,等等等,无不意味 ...

  9. [ Shell ] 通过 Shell 脚本导出 GDSII/OASIS 文件

    https://www.cnblogs.com/yeungchie/ 常见的集成电路版图数据库文件格式有 GDSII 和 OASIS,virtuoso 提供了下面两个工具用来在 Shell 中导出版图 ...

  10. numpy教程04---ndarray的索引

    欢迎关注公众号[Python开发实战], 获取更多内容! 工具-numpy numpy是使用Python进行数据科学的基础库.numpy以一个强大的N维数组对象为中心,它还包含有用的线性代数,傅里叶变 ...