2012 不宜进入的三个技术点(下)

赖勇浩(http://laiyonghao.com

C++

C++ 在 2011 年其实风头甚劲,C++2011 标准出台,gcc/msvc/clang 都很快速地支持了许多新特性,新兴的移动设备的性能较差,更是 C++ 的新舞台,在这个时候唱衰 C++,压力很大。我使用 C++ 年头不少,但除了在校的时候写过两个小游戏参加过两个比赛(分别是面向社会和面向大学生的)弄些证书好找工作以外,在工作中只用过大概不到一年半,做《斩魂》(http://zh.163.com)的早期版本,写了服务器端的几条进程和客户端的 GameAI 部分。经验少,而且写得不好,所以基本上有人在 weibo 上问我 C++ 的问题,我都是转发给 @bnu_chenshuo@miloyip 等真正的行家去回答的。所以实际上今天写这一篇,我底气很是不足,但是朋友们给前两篇很大面子,弄得我骑虎难下,只好硬着头皮写了。
前文提到 C++ 的新标准,很有必要提一下标准化对 C++ 的影响。首先我们要肯定标准定制对 C++ 的积极作用,但标准化过程中的超长流程,一次次将 C++ 推向深渊。C++ 的第一个标准是 1998 年的 ISO/IEC 14882:1998,距离整个 90 年代最流行的 C++ 程序库 MFC(Microsoft Foundation Class Library)的第一个版本发行时间已经整整  6 年。1998 年,MFC 版本号为 6.0,与其一起发布的 Visual C++ 6.0 占有了巨大的市场。因为 MFC 发布得标准制定的时间早,所以 MFC 内部实现了许多后来标准库里也有的组件,比如各种数据结构容器。VC6 的市场占有率让 windows 平台下开发的许多 C++ 程序员甚至不知道有 STL,同时也无视 C++98 标准,从更兼容标准的 VC2002/2003 的市场占有率就可以看出来,直到今天,我知道国内不少公司还是只用 VC6 的。
其实在 90 年代,计算机的运算能力有限,市场上非常需要一款性能较高、抽象较强的编程语言,C++ 获得了成功,但它标准化的时间过长,造成各种编译器有各自互不兼容的“方言”,成了它的第一个软肋。第一个瞄准这个软肋的就是 java,java 在 1995 年推出,虽然性能稍逊,但它有更高的抽象能力、也更安全,并且更容易跨平台,所以迅速获得了成功;第二个瞄准这个软肋的是 C#,微软不能推动 C++ 发展,又不愿 C++ 的市场被 java 鲸吞,于是在 2001 年推出了 C#,经过 10 年的发展和微软大量的金钱推广,C# 已经成功获得了它应有的江湖地位。
虽然 java/c# 都不是善类,但 C++ 在 21 世纪的第一个十年里仍然地位稳固,这是因为 Linux 和 MacOS X 大获成功,在这两个平台上 C++ 都是非常有竞争力的编程语言,C++ 自然水涨船高。但随着 web2.0 和 web app 概念的兴起,以及 CPU 的主频进一步提升,服务器端编程语言渐渐地对执行效率不再敏感,而是更在意程序员的开发效率,众多的脚本语言开始蚕食 C++ 的市场份额,从早期的 perl 到后期的 python/php/ruby,在 2005 年以后,C++/java/C# 等静态类型的编译型语言的市场份额都下降了,新兴的贵族是动态语言。面对动态语言在开发效率上的强劲挑战,C++ 社区除了在 2003 年对 C++98 做了小小的 patch,基本上睡着了,完全没有应对之策,哦不,连应用的姿态都没有。
进入 21 世纪的第二个十年,市场又发生了变化,云计算越走越近,也许我们中的大部分人今天还可以说只闻其声不见其形,但 The Data Center Is the Computer 这句话大家应该觉得很务实:完成一个用户操作,在服务器端的进程间通信次数前所未有地多。在这个十年,我们需要这样的编程语言:
1、能充分利用现代 CPU 的计算能力,不仅仅是多个核心,更是巨大的 L1/L2/L3 Cache、超线程等;
2、能够大量减小异步 I/O 的性能提升的同时带来的副作用:异步编程的复杂性以及对可维护性的伤害;
两句话其实也可以压缩为一句:需要有更好的并发模型的语言。一开始大家都在已有的编程语言中寻找,然后找到了 erlang,实践证明 erlang 自有其局限,所以 google go/scala/rust 等新语言如同雨后春笋般拨地而出。C++2011 标准努力降低 C++ 的编程难度,并提供了线程库以支持现代 CPU,如果在 2005 年,这个标准绝对有竞争力,但在今天,它只能成为新的编程语言的垫脚石。正如 IE 最大的用处是用来下载其它浏览器,不久之后,也许会流行新的冷笑话:C++ 最大的用处就是用来实现其它编程语言。
市场一直在寻找一门中间的高级语言,它上承 C 语言和汇编语言,下启脚本语言。C++ 最先抢占了高地,并在与 java/c# 的争斗中不落下风,但新的十年,它的对手又增加了 google go/scala/rust 等新锐,并且新的标准不可能在两三年内再次出台,两三年内新锐成长起来后,留给它的位置就不多了。
上文讨论的基本上都是服务器编程,有必要再来看一下桌面和移动设备领域。首先看桌面软件,rust 是 mozilla 基金会开发系统程序语言的,它的定位是部分取代 C++ 开发 firefox 的浏览器,所以 rust 会进入桌面开发,google go 肯定会顺道啃一口。移动设备方面,主要是 android、ios 和 windows phone,随着移动设备性能增强,编译型语言加脚本的模式就会占大头,编译型语言方面主要是 C++ 和 Objective-C 在竞争,C++ 会占上风(但需求量远远小于脚本,从 lua 在 2011 年的增长速度可以印证),但是谁知道 rust 之类的会不会进入移动设备呢,毕竟移动设备的 CPU 核心也越来越多了呀,C++ 还是前景堪忧。
回首 C++ 的 30 年,展望它的未来,总结起来可能就是:标准化流程拖死人了。如果不是 15 年不能标准化,java/c# 的搅局可能不会出现;如果在 2005 年能够应对动态语言……如果云时代有更好的并发模型……
题外话:java/c# 不会有 C++ 的问题,因为它们有自己的平台,有巨大的财富支撑。特别是平台的作用非常巨大,你可以想像一下如果 Adobe 有自己的浏览器或手机操作系统 ActionScript/MXML 会不会是今天的境地;也可以想像一下 google go 的飞速发展动力是什么。

两点解释

1、我觉得有必要解释“不宜进入”一下这四个字,我想要表达的意思就是如果你现在不是这三个技术点的专家,并且手上没有使用这三个技术点的项目,进入这三个技术点仅为技术储备,那么就“不宜进入”。另外我不是说用了这三个技术点的项目就死,学了这三个技术点的人就找不到工作,或者这三个技术点明天或明年就 game over,渣都没得剩,不是这样的意思,它们还会存在很长一段时间。本文不是叫专家自废武功,也不是叫已经做好技术造型的项目赶紧儿换技术,举例说,如果你选择了用 java 做服务器端,flash 做客户端开发一个 webgame,那你最好玩命儿地把 ActionScript/MXML 和 java 多线程编程(及异步 I/O)给钻透,不然可能随时掉陷阱里。
2、新年新气象,工作和家庭都有很重要的事情压在肩上,大家的评论我不逐条回复了,我会在一两个星期后再统一写一篇《2012 不宜进入的三个技术点(Q&A)》统一回答,还请见谅。


<think>嗯,用户想了解中断处理函数执行时间过长的原因和影响。这个问题涉及到操作系统和嵌入式系统的核心机制,需要从硬件响应、调度机制和实时性几个角度解释。 用户可能正在学习操作系统内核开发或者嵌入式编程,遇到了中断处理相关的性能问题。从引用[1]和[2]来看,用户已经接触过系统调度和单片机串口中断的案例,但需要更系统的理论解释。 核心问题其实有三个层面:首先是硬件层面,中断本质是抢占CPU的硬件信号,长时间不返回会导致中断丢失(如串口数据覆盖);其次是系统层面,调度器在中断期间被冻结,所有进程都会"卡住";最后是实时性要求,像RTC秒中断这样的场景必须及时响应。 特别要注意引用[1]提到的"调度关闭"机制——这是理解整个问题的关键。当CPU处于中断上下文时,内核会暂时禁用调度器,就像交通警察在路口处理事故时让所有车辆暂停通行。如果事故处理太久,整条路就会瘫痪。这个比喻可能帮助用户理解。 用户提供的引用[3]中那个STM32的案例很典型,在RTC中断里做串口发送导致系统卡死,正好印证了理论。应该强调这种错误在实际开发中很常见,建议用标志位+主循环处理的模式替代。 最后需要提醒用户,虽然引用[4]提到JavaScript单线程机制有相似性,但硬件中断的不可打断性更极端。浏览器至少还有事件队列,而硬件中断是直接剥夺CPU控制权的。</think>中断处理函数执行时间过长会引发严重后果,主要原因和影响如下: --- ### **一、核心原因** 1. **中断上下文特殊性** - **调度被禁用**:进入中断时系统会关闭调度器(避免嵌套中断导致状态混乱),此时CPU无法切换进程[^1]。 - **无法睡眠/阻塞**:若在中断中调用睡眠函数(如`msleep()`),系统因调度关闭无法唤醒其他进程,直接导致死锁[^1]。 2. **硬件中断机制限制** - **中断抢占性**:高优先级中断可抢占低优先级中断,但同级/低级中断会被阻塞。 - **中断丢失风险**:若当前中断未及时返回,新中断可能被丢弃(如串口数据覆盖未处理的数据)[^2]。 --- ### **二、主要影响** | **影响类型** | **具体表现** | |--------------------|-----------------------------------------------------------------------------| | **系统崩溃** | 中断中调用阻塞函数 → 调度器无法运行 → 系统死锁[^1] | | **数据丢失** | 新中断数据覆盖未处理的旧数据(如串口接收缓存区被覆盖)[^2] | | **实时性破坏** | 高优先级任务(如电机控制、传感器采样)无法及时响应 | | **资源耗尽** | 中断嵌套过深 → 栈溢出(STM32等单片机常见问题)[^3] | | **性能劣化** | CPU长时间陷于中断 → 用户进程无法执行 → 系统卡顿 | --- ### **三、典型案例分析** 1. **串口中断延迟处理** - **场景**:在串口中断函数中延时10秒 - **后果**:后续数据持续覆盖缓冲区 → 仅能读取最后一次接收的数据[^2]。 - **原理**: ```c void USART_IRQHandler() { byte = USART_ReceiveData(); // 读取字节 delay(10000); // 延时导致新数据覆盖缓冲区 process(byte); // 实际处理的可能是被覆盖后的数据 } ``` 2. **RTC中断中调用耗时操作** - **场景**:在STM32的RTC秒中断中发送长串口数据 - **后果**:中断阻塞导致定时精度失效,后续中断堆积引发系统卡死[^3]。 --- ### **四、解决方案** 1. **中断设计原则** - **快进快出**:仅做关键状态记录(如设置标志位、复制数据到缓存区)。 - **任务分离**:耗时操作移交主循环或内核线程(如Linux的`tasklet`或`workqueue`)[^1]。 2. **优化技术** - **硬件缓冲**:启用串口FIFO缓冲多字节数据,减少中断触发频率[^2]。 - **中断嵌套**:合理配置中断优先级(仅限支持硬件嵌套的MCU)。 - **轮询混合**:非实时任务改用轮询模式(如查询I²C状态寄存器)。 --- ### **总结** > 中断的本质是**紧急事务响应**,而非任务处理。其执行时间需控制在微秒级,否则将破坏系统实时性并引发连锁故障。开发者应严格遵循"中断瘦身"原则,将复杂逻辑移至主循环或内核线程[^1][^2]。 ---
评论 123
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值