从源码角度解析C++20新特性如何简化线程超时取消
为什么需要超时控制超时控制是很常见的需求最普遍的场景是为了防止程序卡住或者长时间占用资源程序会主动取消掉一些超过允许运行时间的或者无响应的线程比如一些耗时很长的网络连接处理线程等。当然用户等得不耐烦了手动点击取消任务执行也勉强可以算在内。通常超时发生或者用户点击取消之后我们都期待线程能迅速终止执行并让整个程序保持一个完整且安全的状态。然而现实是复杂的想实现上述功能对于线程来说是一件难事尤其在Linux系统上。第一个难点是如何让线程知道自己要退出。对于进程来说这不是难点因为不管进程在做什么我们都可以靠向其发送信号来立即中断进程的执行前提是线程没有屏蔽这个信号这样进程的停止请求可以被立即感知到进程从而可以尽快完成善后工作退出执行。同样的招数对多线程程序来说就没那么好用了——信号默认是发给整个进程的为了能让每个线程独立地接收信号我们需要保存线程的标识符并在每个线程中设置接收和屏蔽信号的mask这大大增加了程序的复杂性其次信号处理函数是整个进程内所有线程共享的我们需要额外的手段来保证并发安全同时还得兼顾信号处理函数需要可重入、快速执行的最佳实践这会提高程序的开发难度。第二个难点在于如何保证线程一定会退出执行。前面说到信号可以打断进程的执行但这只是通知实际上进程完全可以在信号处理函数返回后无视这个通知继续运行或者有一种更普遍的场景——程序正好卡在某个系统调用上而程序又设置了系统调用被信号中断后自动重启这样即使我们有效通知了进程进程也会在收完通知之后再次进入系统调用从而无法响应停止请求。所以作为保底手段Linux可以发送SIGKILL这个信号强制终止进程这个信号无法捕获也无法屏蔽是我们货真价实的“底牌”。上述的情况在多线程中同样存在而且我们没有“底牌”可用——因为不管给哪个线程发送SIGKILL都会杀死整个进程而不是单独接收到信号的那个线程。另外即使有办法强制终止线程比如早期的JVM我们还会遇到资源释放的问题。进程退出执行之后内核会尽可能释放进程持有的所有资源打开的文件会被关闭缓冲区的内容会被刷新文件锁之类的同步机制也会正常解锁但线程并没有这种自动清理机制清理工作完全需要手动执行一旦进程没有释放自己持有的资源就退出系统就会遇到各种数据损坏和死锁等并发问题排查和修复会极其困难。为了克服上述难点并安全高效地实现终止超时线程的执行我们需要一些额外的控制手段。这也一直都是开发者中的热门话题。在介绍C20如何简化超时控制之前我们先来看看前人的智慧成果。Golang实现超时控制Golang是天生支持并发的语言这一点可谓名副其实尤其是在超时控制上。我们直接看个例子例子里有主线程和工作线程工作线程超时时间为5秒如果超过这个时间还有线程没完成工作就取消所有线程的执行。Golang里没有系统级的线程但我们可以用goroutine模拟。在工作线程中我们用sleep代替耗时的工作这样便于测试func Work(ctx context.Context, id int) error {for range 10 {select {case -ctx.Done():fmt.Printf(worker %d: canceled\n, id)return ctx.Err()default:}if rand.IntN(2) 0 {time.Sleep(500 * time.Millisecond)} else {time.Sleep(time.Second)}}fmt.Printf(worker %d: done\n, id)return nil}超时控制是ctx参数实现的每次循环处理前我们都会主动检查线程是否需要退出这种协作式的“请求-检查-响应”是各种语言中取消线程执行的常见做法。这个工作函数执行时间在5秒到10秒之间取值的步长在0.5秒加上go标准库默认随机数是均匀分布的所以整体执行时间的概率是正态分布的在7.5秒左右我们很容易看到超时和正常运行结束两种情况。所以我们把超时时间分别设为4秒、7.5秒、11秒来进行模拟运行实验func main() {// 从命令行获取超时时间单位毫秒timeout, err : strconv.Atoi(os.Args[1])if err ! nil {panic(err)}ctx, cancel : context.WithTimeout(context.Background(), time.Duration(timeout)*time.Millisecond)now : time.Now()defer cancel()g : errgroup.Group{}for i : range 3 {g.Go(func() error {return Work(ctx, i)})}err g.Wait()fmt.Printf(run time: %s\n, time.Since(now))if err ! nil {if errors.Is(err, context.DeadlineExceeded) {fmt.Println(Tasks canceled)return}panic(err)}fmt.Println(All work done!)}代码很简单关键在这行ctx, cancel : context.WithTimeout(context.Background(), 7500*time.Millisecond)只要我们设定的时间到了-ctx.Done()就会从阻塞变为非阻塞循环开始处的检查会发现这个变化然后会退出线程的执行。代码中使用了errgroup但这不是必须的实际上有很多办法可以通知主线程这里我选择了一种最通用的代价是代码会稍微复杂一些。运行代码会看到下面这样的输出结果有很大的随机成分下面只是无数种可能中的一种$ go build -o test$ ./test 4000worker 1: canceledworker 0: canceledworker 2: canceledrun time: 4.00431275sTasks canceled$ ./test 7500worker 0: doneworker 2: doneworker 1: canceledrun time: 7.507776458sTasks canceled$ ./test 11000worker 1: doneworker 2: doneworker 0: donerun time: 8.509193125sAll work done!可以看到超时控制发挥了作用尽管内置的time计时有一些误差但程序的总体的运行时间是小于等于超时时间的。Golang的超时控制可以通过context简单实现但需要工作线程主动检查主动配合前文我们也提到了强制终止工作线程很可能会造成并发问题因此所有的线程超时控制中都是采用的这种协作式退出机制即使天生并发的语言也不能免俗。作为代价我们需要谨慎编码以免工作线程无法响应退出请求同时还需要付出一点在循环里检查是否需要退出执行的性能损失。C中的典型超时控制实现c没有方便好用的context想要实现协作式退出得自己造轮子。Golang好用是因为标准库和运行时调度器隐藏了实现的细节WithTimeout实际上会创建一个定时器到时间后调度器会执行定时器的回调函数主动关闭ctx内部的channel这样-ctx.Done()就会从阻塞变成非阻塞协程就能检查到这一变化从而退出执行。核心只在于两点以合适的方法标记线程已被取消和异步地在超时后设置取消标记。

相关新闻

5分钟快速上手:中国车牌生成器终极指南 - 免费开源车牌图像生成工具

5分钟快速上手:中国车牌生成器终极指南 - 免费开源车牌图像生成工具

5分钟快速上手:中国车牌生成器终极指南 - 免费开源车牌图像生成工具 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 在计算机视觉、车牌识别算法开发和自动…

2026/7/2 0:53:23阅读更多 →
大电流BLDC电机FOC控制方案与STM32实现

大电流BLDC电机FOC控制方案与STM32实现

1. 项目背景与核心挑战在工业自动化、机器人关节控制和精密仪器领域,无刷直流电机(BLDC)的高性能控制一直是工程师面临的技术难题。传统六步换相控制虽然实现简单,但存在转矩脉动大、效率低下的问题。而磁场定向控制(F…

2026/7/2 0:53:23阅读更多 →
SQL查询结果导出总报错、乱码、截断?,深度解析IDEA 2023.3+版本导出引擎底层机制

SQL查询结果导出总报错、乱码、截断?,深度解析IDEA 2023.3+版本导出引擎底层机制

更多请点击: https://kaifayun.com 第一章:SQL查询结果导出总报错、乱码、截断?,深度解析IDEA 2023.3版本导出引擎底层机制 IntelliJ IDEA 2023.3 起重构了 Database Tools 的导出子系统,将原先基于 Swing UI 的同步导…

2026/7/2 0:53:23阅读更多 →
单纯换同义词没用!深度语义改写原理,解锁高效降重方式

单纯换同义词没用!深度语义改写原理,解锁高效降重方式

2026 年知网、维普、万方、Turnitin 等学术检测系统已全面升级AIGC 双检测模块,不再只依靠字符串匹配判定重复,而是通过困惑度(Perplexity)、文本突发度(Burstiness)、N-gram 词频分布三大统计特征识别 AI …

2026/7/2 2:03:30阅读更多 →
列表的通用操作

列表的通用操作

list_str list("zhang") print(f字符串转列表:{list_str})print("新增") list_one [1,2,3] list_one.append(4) print(fappend在列表最后插入:{list_one}) list_one.insert(0,0) print(finsert按照索引位置插入:{list_…

2026/7/2 2:03:30阅读更多 →
生产级 Go 代码 Review 清单——从命名规范到并发安全的系统性审查

生产级 Go 代码 Review 清单——从命名规范到并发安全的系统性审查

生产级 Go 代码 Review 清单——从命名规范到并发安全的系统性审查 一、Code Review 的投入产出比:为什么必须系统化 在 Go 项目的生产环境中,Code Review 的投入产出比常常被低估。根据 GitHub 发布的 Octoverse 报告数据,团队在引入系统性 …

2026/7/2 2:03:30阅读更多 →
生活中很多东西都可以用向量描述,比如:

生活中很多东西都可以用向量描述,比如:

🚗 速度(你开车 60 km/h 向东)🌬️ 风(风速 5 m/s 向北)📦 力(用 10 牛顿的力推箱子向右)坐标表示在数学里,我们通常用坐标来表示向量;而在几何空…

2026/7/2 2:03:30阅读更多 →
AI 辅助:高性能 RPC 框架设计:延迟预算要从协议层开始

AI 辅助:高性能 RPC 框架设计:延迟预算要从协议层开始

AI 辅助:高性能 RPC 框架设计:延迟预算要从协议层开始 一、RPC 不是套一层 HTTP 就结束 高性能 RPC 框架要处理连接复用、序列化、压缩、超时、重试、负载均衡、背压和可观测性。业务看到的是一次函数调用,底层其实是一整套网络系统。如果协议…

2026/7/2 2:03:30阅读更多 →
[CSP 2025]游记

[CSP 2025]游记

循环结构 字符串&#xff0c;橙题&#xff0c;不说了肯定做出来了。#include<bits/stdc.h>using namespace std;#define int long long#define N 2000005 int top,a[N];string s;signed main(){cin>>s,s" "s;for(int i1;i<s.length();i) if(s[i]>…

2026/7/2 1:58:29阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月&#xff0c;Boris Cherny 公开宣布自己卸载了 IDE。一时间&#xff0c;Vibe Coding 成了全行业最热的话题。6个月后&#xff0c;当我们回过头来拉一份真实账本&#xff0c;发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/7/1 4:42:14阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言&#xff1a;审计结束三个月了&#xff0c;审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间&#xff0c;内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中&#xff0c;审计…

2026/7/1 5:19:01阅读更多 →
塞尔达传说旷野之息存档修改器:3分钟掌握海拉鲁世界自由定制技巧

塞尔达传说旷野之息存档修改器:3分钟掌握海拉鲁世界自由定制技巧

塞尔达传说旷野之息存档修改器&#xff1a;3分钟掌握海拉鲁世界自由定制技巧 【免费下载链接】BOTW-Save-Editor-GUI A Work in Progress Save Editor for BOTW 项目地址: https://gitcode.com/gh_mirrors/bo/BOTW-Save-Editor-GUI 想在《塞尔达传说&#xff1a;旷野之息…

2026/7/2 0:03:01阅读更多 →
告别 AccessKey:多云平台 CLI OAuth 免密认证完全指南

告别 AccessKey:多云平台 CLI OAuth 免密认证完全指南

在本地开发环境使用云厂商 CLI 时,传统的 AccessKey(AK)方式需要手动创建、下载和保管密钥,不仅繁琐,还存在泄漏风险。其实,主流云平台都已提供基于 OAuth 2.0 的免密认证方案,让开发者可以通过浏览器登录一次性完成授权,CLI 自动管理临时凭证的刷新,兼顾了便利与安全…

2026/7/2 0:03:01阅读更多 →
基于13DOF传感器与PIC32MZ的高精度嵌入式导航系统设计

基于13DOF传感器与PIC32MZ的高精度嵌入式导航系统设计

1. 项目背景与核心价值在嵌入式系统开发领域&#xff0c;高精度定位与导航一直是极具挑战性的技术方向。传统方案往往面临成本、精度和实时性难以兼顾的困境。这个项目通过13DOF&#xff08;13自由度&#xff09;传感器组合与PIC32MZ2048EFH100高性能MCU的协同工作&#xff0c;…

2026/7/2 0:03:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时&#xff0c;发现推理速度只有可怜的 1-2 FPS&#xff0c;而别人的演示视频却能跑到 30 FPS 以上&#xff0c;那么问题很可能不在模型本身&#xff0c;而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后&#xff0c;会直接使用官方示例…

2026/7/2 0:33:58阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一&#xff1a;为什么你需要了解 Coze 和 Dify&#xff1f;如果你对 AI 应用开发感兴趣&#xff0c;但一看到“大模型”、“智能体”、“工作流”这些词就头疼&#xff0c;觉得门槛太高&#xff0c;那这篇文章就是为你准备的。很多开发者&#xff0c;包括我自己&#…

2026/7/2 1:32:11阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会&#xff1a;配图一直是个让人头疼的问题。2026年&#xff0c;AI生图工具已经非常成熟了&#xff0c;但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1&#xff1a;速度之王2026年6月11日&#xff0c…

2026/7/2 1:50:13阅读更多 →