【C#】Thread.Join()、异步等待和直接join

JogThread.Join() 是 .NET 中 System.Threading.Thread 类的一个方法,用来让当前调用线程暂停执行,直到目标线程(这里是 JogThread)终止为止。以下是它的核心语义和你在 UI 代码里需要注意的几个相关知识点。


1. Thread.Join() 的作用

  • 阻塞调用线程:当你在 A 线程上调用 someThread.Join(),A 线程会停在这一行,直到 someThread 运行完毕(自然退出或抛异常结束)。
  • 无返回值:标准的 Join() 会一直等,没有超时;也有重载 Join(int millisecondsTimeout),可以设置最长等待时间。
// workerThread 是另一个正在执行的线程
workerThread.Start();
// … 做点别的 …
workerThread.Join();  
// 只有当 workerThread 完全结束后,下面这一行才会执行
Console.WriteLine("workerThread 已退出");

2. IsAliveJoin 常见组合

if (JogThread != null && JogThread.IsAlive)
{JogThread.Join();
}
  • IsAlive 检查线程还存活(没终止)再调用 Join
  • 否则如果 Join 在已经结束的线程上调用,.NET 会立刻返回,不会抛异常。

3. winform中在 UI 线程上调用 Join 会带来什么?

  • UI 冻结:WinForms/WPF 的 UI 线程负责不停地处理消息队列(鼠标点击、重绘、动画等)。一旦你在 UI 线程上执行 .Join(),它就不再处理消息,界面完全卡住,直到子线程终结。
  • 无法交互:用户点击按钮、拖动窗口都没有反应,甚至操作系统会提示“应用无响应”。

4. 界面卡在了 Join 那里的原因?

  • 若是按钮事件处理器本身就在 UI 线程上。
  • 当用户点击“xxxx’”触发逻辑时,如果代码进入了 if (JogThread.IsAlive) JogThread.Join();,UI 线程就停在那里等后台 JogThread 结束。
  • JogThread 可能又在等待 UI 线程释放某个资源或控件,结果双向等待 —— 死锁

5. 如何避免 UI 线程被 Join 阻塞?

5.1 用异步等待而不是直接 Join

把阻塞 Join 的工作扔到后台去,再用 await 回到 UI 线程:

// 在 async 方法里
if (JogThread != null && JogThread.IsAlive)
{await Task.Run(() => JogThread.Join());
}

这样,UI 线程发起 await 后会挂起这次事件但继续处理消息。

5.2 完全移除 Join,改成事件/回调

  • 在后台线程跑完后,触发一个事件(如 JogFinished),让 UI 在回调里恢复按钮:
// 后台线程结束时
JogFinished?.Invoke(this, EventArgs.Empty);// UI 订阅该事件
jogService.JogFinished += (_,__)=>this.Invoke(() => { btnPos.Enabled = btnNeg.Enabled = true; });

这样根本不需要在 UI 线程上等待。

5.3 用更现代的 Task 代替 Thread

  • 如果你把 RunJogThread_pJog 改为返回 Task 的异步方法,就可以直接 await 它,而不用操心 Join

    await jogService.RunJogAsync();
    // 到这儿就表示后台跑完了
    

6. 其他

  • 线程安全:任何跨线程操作 UI 控件都必须用 Invoke/BeginInvoke 回到 UI 线程。
  • 超时等待Join(int timeout) 可以避免无限期挂起。
  • 取消机制:配合 CancellationToken,让后台线程在收到取消请求后优雅退出,不靠死等。
  • 后台线程与前台线程Thread.IsBackground 属性决定程序退出时是否等待该线程结束。

异步等待而不是直接 Join

简单来说,二者的核心区别在于:


1. 调用线程是否被 阻塞

  • 直接 Join()

    // 运行在 UI 线程里
    if (jogThread.IsAlive)jogThread.Join();  // ★ 这里 UI 线程被堵住,什么消息都收不到
    

    Join() 会立刻“把调用它的线程”停住,直到目标线程结束——UI 线程一停,就不会刷新界面、响应点击或重绘。

  • 异步等待

    // async 方法里,仍在 UI 线程开始
    if (jogThread.IsAlive)await Task.Run(() => jogThread.Join());
    // ★ 这里 UI 线程会把控制权让出去(继续处理消息),等后台完成后再回来
    

    Task.Run(() => Join()) 会把“等待 Join() 完成”这件事拿到线程池线程上去做,await 则让当前(UI)方法“挂起”,释放 UI 线程去做别的事,等后台那块儿真正完成后再把结果继续推回 UI 线程。


2. UI 响应性

  • Join(): 长时间等待会让界面“卡死”——看起来像“假死”或“无响应”。
  • await Task.Run(...): 等待期间 UI 线程依然可以处理鼠标、键盘、重绘等消息,保持流畅。

3. 异常与超时控制

  • Join(): 没有超时,你只能堵着等;如果想超时要用 Join(timeout),还得写判断逻辑。
  • Task.Run(...); await: 可配合 CancellationTokenTask.WhenAny + Task.Delay 做超时、取消都更自然。

4. 代码可维护性

  • 同步阻塞 风格的代码嵌套过多会变得难读。
  • 异步/await 风格能让“先发起、然后等结果再继续”写得像直线流程,也更容易和现代异步 API(I/O、网络、定时器)配合。

小对比表

Join()await Task.Run(() => Join())
调用线程同一线程(可能是 UI)把阻塞逻辑转到线程池线程,UI 线程自由
UI 响应★ 卡死、假死✓ 保持流畅
超时/取消需要 Join(timeout) 或额外判断可轻松配合 CancellationTokenTask.Delay
代码直观度同步嵌套易混乱异步/await 更自然,易读

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

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

相关文章

牛客网NC22012:判断闰年问题详解

牛客网NC22012:判断闰年问题详解 📝 题目描述 题号:NC22012(牛客网) 时间限制:C/C/Rust/Pascal 1秒,其他语言2秒 空间限制:C/C/Rust/Pascal 32 M,其他语言64 M 判断一个…

鸿蒙开发——1.ArkTS声明式开发(UI范式基本语法)

鸿蒙开发——1、ArkTS声明式开发:UI范式基本语法 [TOC](鸿蒙开发——1、ArkTS声明式开发:UI范式基本语法)一、ArkTS的基本组成(1)核心概念(像贴标签一样控制组件)(2)基础工具包(现成的积木块&am…

【SPIN】PROMELA语言编程入门基础语法(SPIN学习系列--1)

PROMELA(Protocol Meta Language)是一种用于描述和验证并发系统的形式化建模语言,主要与SPIN(Simple Promela Interpreter)模型检查器配合使用。本教程将基于JSPIN(SPIN的Java图形化版本)&#…

Automatic Recovery of the Atmospheric Light in Hazy Images论文阅读

Automatic Recovery of the Atmospheric Light in Hazy Images 1. 论文的研究目标与实际意义1.1 研究目标1.2 实际问题与产业意义2. 论文的创新方法、模型与公式2.1 方法框架2.1.1 方向估计(Orientation Estimation)2.1.2 幅值估计(Magnitude Estimation)2.2 与传统方法的对…

基于微信小程序的在线聊天功能实现:WebSocket通信实战

基于微信小程序的在线聊天功能实现:WebSocket通信实战 摘要 本文将详细介绍如何使用微信小程序结合WebSocket协议开发一个实时在线聊天功能。通过完整的代码示例和分步解析,涵盖界面布局、WebSocket连接管理、消息交互逻辑及服务端实现,适合…

速通:国际数字影像产业园园区服务体系

速通:国际数字影像产业园园区服务体系 国际数字影像产业园服务体系致力于构建全周期、多维度、高效率的产业赋能平台,旨在优化营商环境,激发企业活力,推动数字影像产业集群化、高端化发展。 一、基础运营与智慧管理服务 智慧化…

DeerFlow:字节新一代 DeepSearch 框架

项目地址:https://github.com/bytedance/deer-flow/ 【全新的 Multi-Agent 架构设计】独家设计的 Research Team 机制,支持多轮对话、多轮决策和多轮任务执行。与 LangChain 原版 Supervisor 相比,显著减少 Tokens 消耗和 API 调用次数&#…

MySQL 大表中添加索引的两种常见方式及其优缺点分析

引言 在数据库性能优化过程中,给大表添加索引是一项常见且重要的操作。由于大表数据量庞大,索引的创建过程往往涉及较高的系统开销和复杂的操作流程。本文将介绍两种在大表中添加索引的常见方法:直接添加索引和表复制方式,分别分…

Ubuntu系统挂载磁盘并配置开机自动挂载

今天买了个服务器然后挂载了一个500G的磁盘,但是登录进去后发看不到,就是下面这样的 只能看到100G的系统盘 rootecm-74de:/usr/local# df -h Filesystem Size Used Avail Use% Mounted on tmpfs 3.1G 1.1M 3.1G 1% /run /dev/vda2 …

Android开发-Application

在Android应用开发中,Application类扮演着非常重要的角色。它作为整个应用程序的全局单例实例存在,在应用启动时最先被创建,并且在整个应用生命周期内持续存在。通过自定义Application类,开发者可以执行全局初始化操作、管理全局状…

边缘计算平台

本文来源 : 腾讯元宝 边缘计算平台是一种在靠近数据源头的网络边缘侧部署的分布式计算架构,通过融合网络、计算、存储和应用核心能力,就近提供实时、低延迟的智能服务。以下是其核心要点: ​​1. 定义与特点​​ ​​定义​​&a…

Spring 框架 JDBC 模板技术详解

一、JDBC 模板技术概述 在传统 JDBC 开发中,开发人员需要手动处理数据库连接(Connection)、事务管理、语句执行(Statement)和结果集(ResultSet)等繁琐操作,不仅代码冗余度高&#x…

Axure难点解决分享:统计分析页面引入Echarts示例动态效果

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 课程主题:统计分析页面引入Echarts示例动态效果 主要内容:echart示例引入、大小调整、数据导入 应用场景:统计分析页面…

SpringBoot 数据校验与表单处理:从入门到精通(万字长文)

一、SpringBoot 数据验证基础 1.1 数据验证的重要性 在现代Web应用开发中,数据验证是保证系统安全性和数据完整性的第一道防线。没有经过验证的用户输入可能导致各种安全问题,如SQL注入、XSS攻击,或者简单的业务逻辑错误。 数据验证的主要…

Ubuntu 22.04(WSL2)使用 Docker 安装 Zipkin 和 Skywalking

Ubuntu 22.04(WSL2)使用 Docker 安装 Zipkin 和 Skywalking 分布式追踪工具在现代微服务架构中至关重要,它们帮助开发者监控请求在多个服务之间的流动,识别性能瓶颈和潜在错误。本文将指导您在 Ubuntu 22.04(WSL2 环境…

python打卡day25@浙大疏锦行

知识点回顾: 1.异常处理机制 2.debug过程中的各类报错 3.try-except机制 4.try-except-else-finally机制 在即将进入深度学习专题学习前,我们最后差缺补漏,把一些常见且重要的知识点给他们补上,加深对代码和流程的理解。 作业&a…

鸿蒙OSUniApp 开发实时聊天页面的最佳实践与实现#三方框架 #Uniapp

使用 UniApp 开发实时聊天页面的最佳实践与实现 在移动应用开发领域,实时聊天功能已经成为许多应用不可或缺的组成部分。本文将深入探讨如何使用 UniApp 框架开发一个功能完善的实时聊天页面,从布局设计到核心逻辑实现,带领大家一步步打造专…

43、Server.UrlEncode、HttpUtility.UrlDecode的区别?

Server.UrlEncode 和 HttpUtility.UrlDecode 是 .NET 中用于处理 URL 编码/解码的两个不同方法,主要区别在于所属命名空间、使用场景和具体行为。以下是详细对比: 1. 所属类库与命名空间 Server.UrlEncode 属于 System.Web.HttpServerUtility 类。通常…

代码随想录 算法训练 Day1:数组

题目一: 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target …

容器技术 20 年:颠覆、重构与重塑软件世界的力量

目录 容器技术发展史 虚拟化技术向容器技术转变 Docker的横空出世 容器编排技术与Kubernetes 微服务的出现与Istio 工业标准的容器运行时 容器技术与 DevOps 的深度融合​ 无服务架构推波助澜 展望未来发展方向 从 20 世纪硬件虚拟化的笨重,到操作系统虚拟…