Task中Wait()和Result造成死锁

news2025/1/20 21:55:42

        在使用Task的时候,一不留神就会造成死锁,而且难以发现,尤其是业务繁多的情况下,一个Task嵌套另一个Task的时候,下面就演示一下,在什么情况下,会产生Wait()和Result的死锁,因此,我们就要避免这样的写法。

目录

一、Wait()死锁

二、Result死锁

一、Wait()死锁

首先执行下面这段代码,点击按钮的时候,界面直接就卡死了。

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            A().Wait();
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task A()
        {
            await Task.Delay(1000);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
        }

如下图所示,而且运行显示的线程是1,也就是在执行A().Wait();时,程序就死了。

死去的原因就是A方法里面,要等待1s,它们都是主线程,所以到了 A().Wait()时,主线程会卡死这里,形成了互相等待的局面,你等我,我等你,就产生了死锁。

解决死锁的方式有2种。

1.只增加一句代码即可

增加.ConfigureAwait(false)

    private void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            A().Wait();
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task A()
        {
            await Task.Delay(1000).ConfigureAwait(false);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
        }

这句的意思就是,让你重新建立一个线程,把主线程让出去,这样就不会死锁了。

此时点击按钮,就会产生一个线程4,等线程4执行完毕后,就回到了主线程上。 

2. 增加await(推荐)

      private async void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            //A().Wait();                                                            //A().Wait();
            await A();
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task A()
        {
            await Task.Delay(1000);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
        }

此时点击按钮,会看到都是同样的线程

虽然都解决了死锁,但是他们的原理是不一样的,第2种,始终都是1个主线程再执行,第1个开启了一个线程,干完事后,又回到了主线程上。

微软也建议我们async到底,一直传染下去。 

二、Result死锁

这种死锁主要是Task中,带有返回的值。

我们改造一下即可

     private void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            string str = A().Result;
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task<string> A()
        {
            await Task.Delay(1000);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
            return "123";
        }

此时点击按钮,界面卡死了

解决方式和上面的一样,同样有2种方式

1.增加.ConfigureAwait(false)

    private void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            string str = A().Result;
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task<string> A()
        {
            await Task.Delay(1000).ConfigureAwait(false);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
            return "123";
        }

点击按钮后,界面就不会卡了,也是创建了一个线程,完成后,回到主线程上面 

2.增加await(推荐)

     private async void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            string str =await A();
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task<string> A()
        {
            await Task.Delay(1000);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
            return "123";
        }

此时点击按钮,界面不卡了,会看到都是同样的线程,和上面的一模一样。

拓展

当我们基于第二部分的第2种方法,加上了.ConfigureAwait(false)

将会有什么变化呢?

代码:

    private async void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);       //获取当前的线程ID
            string str =await A();
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

        private async Task<string> A()
        {
            await Task.Delay(1000).ConfigureAwait(false);
            Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
            //业务代码
            return "123";
        }

效果 

界面也不卡了,但是发现到,界面还是开启了一个线程,然后回到主线程上,虽然他们的功能都是一样的,但是这种方法肯定不如单个主线程好,因为开启一个线程,也需要耗费资源。 

所以,ConfigureAwait(false)这句代码非常的重要,界面是否卡死,就是他的原因,意思就是是否立即返回主线程干活,true是,false否。

当我们改成true,又是单个主线程执行了,此时,其实ConfigureAwait(true)是句无效的代码,因为就算你返回了,那边还有一句await,await主线程,都是在一个线程上。

来源:

Task中Wait()和Result造成死锁-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1280127.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法训练营 ---第五十二天

第一题&#xff1a; 简介&#xff1a; 动态规划五部曲&#xff1a; 1.确定 dp数组下标的定义 dp[i] 到达 i 时 最长递增子序列的长度 2.确定递推公式 我们确定当前的最大长度需要遍历前面所有的最大长度&#xff0c;然后如果序列最后一个值小于nums[i]那就dp[j] 1&#xf…

Kubernetes1.27容器化部署Prometheus

Kubernetes1.27容器化部署Prometheus GitHub链接根据自己的k8s版本选择对应的版本修改镜像地址部署命令对Etcd集群进行监控&#xff08;云原生监控&#xff09;创建Etcd Service创建Etcd证书的Secret创建Etcd ServiceMonitorgrafana导入模板成功截图 对MySQL进行监控&#xff0…

java+springboot物资连锁仓库经营商业管理系统+jsp

主要任务&#xff1a;通过网络搜集与本课题相关的素材资料&#xff0c;认真分析连锁经营商业管理系统的可行性和要实现的功能&#xff0c;做好需求分析&#xff0c;确定该系统的主要功能模块&#xff0c;依据数据库设计的原则对数据库进行设计。最后通过编码实现本系统功能并测…

进行主从复制时出现的异常FATAL CONFIG FILE ERROR (Redis 6.2.6)Reading the configuration file

错误如下所示&#xff1a; FATAL CONFIG FILE ERROR (Redis 6.2.6) Reading the configuration file, at line 1 >>> include/myredis/redis.conf Bad directive or wrong number of arguments出现错误的原因是.conf文件中命令之间缺少空格&#xff0c;如下所示&…

树莓派多串口通信

树莓派多串口通信 串口配置串口通信函数分析串口通信示例代码 参考博文1&#xff1a;树莓派 4 UART 多串口配置通信参考博文2&#xff1a;树莓派wiringPi库详解关于树莓派相关其他环境配置可参考&#xff1a;快速上手树莓派关于wiringPi库初始化与IO口开发可参考&#xff1a;树…

若依框架分页

文章目录 一、分页功能解析1.前端代码分析2.后端代码分析3. LIMIT含义 二、自定义MyPage,多态获取total1.定义MyPage类和对应的调用方法 一、分页功能解析 1.前端代码分析 页面代码 封装的api请求 接口请求 2.后端代码分析 controller代码 - startPage() getDataTable(…

智能优化算法应用:基于动物迁徙算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于动物迁徙算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于动物迁徙算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.动物迁徙算法4.实验参数设定5.算法结果6.参考…

HTML5+CSS3+Vue小实例:浪漫的心形文字动画特效

实例:浪漫的心形文字动画特效 技术栈:HTML+CSS+Vue 效果: 源码: 【HTML】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" conte…

Linux 命令stat

命令作用 stat命令用于显示文件的状态信息。stat命令的输出信息比ls命令的输出信息要更详细。 查看的信息内容: File 显示文件名 Size 显示文件大小 Blocks 文件使用的数据块总数 IO Block IO块大小 regular file 文件类型&#xff08;常规文件&#xff09; Device …

SmartsoftHelp8,条形码,二维码 生成,解析 专业工具

生成条形码 生成二维码 条形码解析 二维码解析 专业工具 下载地址&#xff1a; https://pan.baidu.com/s/1zBgeYsqWnSlNgiKPR2lUYg?pwd8888

Web前端JS如何获取 Video/Audio 视音频声道(左右声道|多声道)、视音频轨道、音频流数据

写在前面&#xff1a; 根据Web项目开发需求&#xff0c;需要在H5页面中&#xff0c;通过点击视频列表页中的任意视频进入视频详情页&#xff0c;然后根据视频的链接地址&#xff0c;主要是 .mp4 文件格式&#xff0c;在进行播放时实时的显示该视频的音频轨道情况&#xff0c;并…

Cairo编程语言

文章目录 Cairo编程语言一、背景二、什么是Cairo工作原理 三、Solidity 和 Cairo 的区别四、开发 Starknet 智能合约的工具链protostarstarknet-foundryScarb安装Scarb 安装starknet-foundry通过snfoundryupStarknet Foundry的snforge 命令行工具如何创建新项目、编译和测试snc…

笔记本电脑关闭触摸板

大部分人用笔记本 其实都是外接的鼠标 那么在打游戏 以及一些切图操作中 为了防止碰到触摸板导致误操作 我们就可以将他关掉 我们可以按快捷键 Win i 或者 点击桌面 此电脑/我的电脑/此计算机 打开设置界面 如果 左侧菜单中有设备 那么 直接点击设备 然后左侧菜单就会有 触摸…

openwrt上开启syslog打印方法

最近在openwrt上调试蓝牙时&#xff0c;出现问题&#xff0c;设备上的蓝牙适配器已经正常工作了&#xff0c;执行pair命令后&#xff0c;openwrt和待连接的设备上都出现了配对码&#xff0c;两边都同意&#xff0c;但连接失败 尝试分析log&#xff0c;发现在如下代码处打印了错…

【Vulnhub 靶场】【Funbox: Lunchbreaker】【简单】【20210522】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/funbox-lunchbreaker,700/ 靶场下载&#xff1a;https://download.vulnhub.com/funbox/FunboxLunchbreaker.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年05月22日 文件大小&#xff1a;1.6 GB 靶…

Docker镜像制作与推送

目录 Docker镜像制作 搭建私服 将本地镜像推送到私有库 Docker镜像制作 以创建一个新ubuntu镜像&#xff0c;并安装vim命令示例 运行一个ubuntu镜像&#xff0c;发现在镜像里面无法使用vim命令&#xff0c;因为该ubuntu镜像只包括了其最基本的内核命令 [rootlocalhost ~]…

BEVFormer环境配置

官网的教程说是Step By Step&#xff0c;但是实际上我按照步骤安装下来运行不了&#xff08;BEVFormer GitHub地址&#xff09;。主要是安装后关于包依赖产生的某些错误&#xff0c;特别是安装nuscenes-devkit没有在步骤中列出来&#xff0c;后面就不好解决某些包的版本依赖了。…

CCFCSP试题编号:202006-2试题名称:稀疏向量

不断匹配相乘累加就好了 #include<iostream> #include<vector> #include <utility> using namespace std;int main() {int n;int a, b;long long result0; // 使用 long long cin >> n >> a >> b;vector<pair<int, int> > u…

经典文献阅读之--Traversability Analysis for Autonomous Driving...(Lidar复杂环境中的可通行分析)

0. 简介 对于自动驾驶来说&#xff0c;复杂环境的可通行是最需要关注的任务。《Traversability Analysis for Autonomous Driving in Complex Environment: A LiDAR-based Terrain Modeling Approach》一文提出了用激光雷达完成建图的工作&#xff0c;其可以输出稳定、完整和精…

【蓝桥杯】带分数

带分数 题目要求用一个ab/c的形式得到一个值&#xff0c;而且只能在1~9里面不重复的组合。 可以对1~9进行全排列&#xff0c;然后不断划分区间。 #include<iostream> #include<vector> using namespace std; int st[15]; int num[15]; int res; int n;int calc(i…