在实时操作系统里随便写代码都能硬实时吗?

这是转发宋老师写的文章,我也是刚知道,宋老师跟我一样也是养娃的人了,国庆期间,看看文章,看看升升国旗。

很久没有写技术文章了,做码农难,做养娃的码农更难,趁着娃看动画片的机会,受着王菲童鞋《我和我的祖国》歌唱精神的鼓舞,我要来说几句。

硬实时是什么?

众所周知,硬实时的概念不是越快越好,而是强调可重复的(repeatable)、决定性的时间期限内给予响应(deterministic response time)。所以它的本质点是可预期,实时系统的计算正确性不仅取决于计算的逻辑正确性,还取决于产生结果的时间。比如,汽车碰撞后,必须在X时间内弹开安全气囊,你弹开晚了,人已经挂了。

当然最恶劣场景下的延迟,可能作为一个时间参数,来评估RTOS本身的性能指标。比如你改造了Linux,实现了中断或高优先级任务的100us以内的确定性延迟;但是RT-Thread,可能不改造,就可以到达us以内的延迟。那么,你延迟要求只需要200us以内的,你选改造后的Linux也没有什么毛病,但是如果你要的就是us级,那么对不起,Linux不是你的菜

众所周知,RT-Thread、FreeRTOS、VxWorks这样的操作系统是硬实时的;Linux这样的操作系统是提供软实时能力的,针对的 miss 掉截止期限也死不了人的那种应用,比如看电影。

那么,这个时候我们诞生了一个疑问,是不是在RTOS里面随便写代码都能满足硬实时,而在Linux里面无论怎么写代码都满足不了硬实时?我认为这2个问题的答案都是否定的。

Linux为什么不硬实时?

我们首先看一下,Linux为什么不能提供硬实时能力。我们认为Linux主要有如下问题(你站在硬实时的角度看它是问题,你换个角度看,它就反而是正确的地方)。

1. spinlock是一个随处可见被内核、驱动使用的API

Linux内核和驱动程序员钟爱spinlock到了如痴如狂的程度,可以说不睡眠、时间较短的critical section场景,都会第一时间想到spinlock。平生不识自旋锁,就称英雄也枉然。自旋锁的优越性在于,在2个人(这2个人可能是线程与线程、中断与线程、中断与中断等)竞争一个锁的时候,避免失败的那一方切换上下文context,所以与其上下文切换,不如原地等。但是自旋锁本身也引起了副作用,它引起了持有锁的CPU核的抢占调度的禁止。内核自旋锁的实现,更多的是核间自旋转而核内是通过禁止抢占来实现临界区保护的。

640?wx_fmt=png

假设T1, T2, T3, T4运行在一个核上面,当T1拿到spinlock后,这个核上的抢占调度被禁止,如果在T1持有spinlock的时间内,T2是一个高优先级的实时任务,尽管T2被唤醒,它也不可能立即打断T1的执行,必须等待T1释放spinlock。由于T1究竟会持有 spinlock 多久做xxxx,这个鬼都不知道,所以T2究竟要等多久,也未可知,这显然破坏了决定性的时延

2. Linux的中断执行时间可能过长且不可嵌套

众所周知,早期的Linux版本有个标记叫IRQF_DISABLED,标记本中断在执行的时候,其他所有中断都被禁止进入;而后Linux内核实际去掉了这个申请flags,其实就是都是IRQF_DISABLED了,总体可认为Linux内核不支持中断的嵌套。

int request_irq(unsigned int irq, irq_handler_t handler,	unsigned long irqflags, const char *devname, void *dev_id);

中断在执行的时候,所有的中断都进不来,这个设计本身简化了内核,但是对于硬实时的打击是致命的,前面的中断不执行完成,优先级再高的中断也得给我等着。

640?wx_fmt=png

比如中断1在执行的过程中,来了中断2,而中断2对应的事情是必须要决定性时延的,由于IRQ1的中断服务程序也是码农写的,我们无法确定这个中断服务程序要执行多久。这显然让高优先级中断2的进入延迟不再具备可预期性。

3.软中断(softirq)是一个比进程上下文优先级更高的上下文

我们设想一个场景,哪怕Linux解决了问题2,就是Linux的中断变地可嵌套,高优先级的中断可以打断低优先级的中断,并且高优先级的中断2唤醒了一个用户写的实时线程。

640?wx_fmt=png

IRQ2唤醒了实时任务T1,但是T1必须等待IRQ1唤起的软中断(也包括使用软中断上下文的tasklet等)被执行完,T1才能投入执行。IRQ1唤起的softirq的代码是码农写的,这个码农写多久,鬼都不知道,这显然破坏了实时任务T1得以调度执行的确定性时延。

4. 内核里面会屏蔽中断的API如local_irq_disable、spin_lock_irqsave等

前面笔者已经反复强调过,在驱动程序里面调用local_irq_disable()通常都是一个bug,因为它无法修复另外一个核上运行的线程、中断服务程序与本核线程之间的竞争。尽管在单核处理器里面调用这个API是通常安全的,但是我们哪怕是在单核编程,都要假装自己是多核的样子,这个是在Linux里面写代码跨平台的最基本常识。

相信绝大多数童鞋都不会傻到写驱动的时候再去调local_irq_disable这样的API。但是spin_lock_irqsave这样的API在内核的使用可以说太常见了,它其实是适用于一个经典的场景,就是中断服务程序与线程之间有竞态的情况。作为一个内核程序员,相信如下的经典用法你已经熟悉地不能再熟悉,满满地都是套路:

640?wx_fmt=png

它把T1、T2、T3、T4、IRQ1、IRQ2这6者之间的竞争消灭于无形。T1如果持有了spin_lock_irqsave,本核上的T2、IRQ1显然进不来,CPU1上面的T3、T4、IRQ2想访问T1访问的临界资源必须spin。IRQ1如果持有了spin_lock, CPU1上面的T3、T4、IRQ2想访问IRQ1访问的临界资源必须spin。

那么,问题又来了,spin_lock_irqsave既屏蔽了抢占,又屏蔽了中断,这会导致中断和实时任务的确定性时延造成不可预期的破坏。因为spin_lock_irqsave 和 spin_lock_irqrestore是码农写的,鬼都不知道它要多久。

当然,历史上,粗犷的大内核锁(Big Kernel Lock,BKL)也是一个问题。由于晶晶姑娘不喜欢内核粗犷的一面,BKL在如今的内核里面已经烟消云散。

在Linux的世界里,这些锁当然都没有一个锁牛逼,就是RCU,尤其是面对这个世界符合阿姆达尔定律(Amdahl's law)定律的情况下,我们既要保证临界资源访问的被保护,又要尽一切可能地让多个线程同时狂奔。关于RCU的细节,谢神医已经有多篇文章论述。

Linux的世界大概是这样的:中断、软中断、线程(包括ksoftirqd线程)。我们都清楚地知道,软中断大量陷入的情况下,内核会将后续的软中断投入ksoftirqd内核线程执行,所以软中断还有一个可能的执行时机是在内核线程里面。

640?wx_fmt=png

5. Linux用户空间内存的lazy分配机制与交换swap

对于喜欢在RTOS写程序的童鞋来说,Linux的世界一时半会难以理解,但是对于写Linux的童鞋来说,绝大多数的RTOS简直就是在裸奔。

我们都知道,在Linux里面,用户空间的内存都执行lazy的分配机制。比如你malloc一个内存

char *p = malloc(1024*1024);

这个时候Linux忽悠你说拿到了内存并且p获得了地址,但是实际的拿到却是在你写的时候,以page fault缺页中断的形式获得的。比如你写p[0]=1就拿到了第一页,你写p[4096]就拿到了第2页。这个lazy的分配机制,也同样适用于栈、代码段等。

你是一个实时的线程,你被唤醒得以执行,你执行的时候,发现你访问的临时变量还没有获得内核,你的代码段可能还特马在硬盘里,请问你实时个什么鬼?你执行到函数b的时候,去访问d[1000],结果发现这个栈的这页内存还要通过page fault来通过内核buddy去申请,你的确定性延迟还如何满足?

main()	
{	…	a();	
}	
a()	
{	…	b();	
}	
b()	
{	int d[1024];	d[1000]=100;	c();	
}

当然,已经进入内存的东西,也由于内核的swap机制,会与磁盘进行交换。

绝大多数的RTOS都没有这个“问题”,这也恰恰是他们不够“牛逼”的地方。对于手机、电脑这种富应用的系统而言,你不能用资源已经被确定性分配的思维模式来思考。

Linux preempt-rt如何解决这些问题?

前段时间,这篇文章刷屏了:《

640?wx_fmt=png

到今天为止,ARCH_SUPPORTS_RT谁他么都不是真:

barry@barryUbuntu:~/develop/linux$ git grep ARCH_SUPPORTS_RT

arch/Kconfig:config ARCH_SUPPORTS_RT

kernel/Kconfig.preempt: depends on EXPERT && ARCH_SUPPORTS_RT

所以,你要真地在mainline见到PREEMPT_RT开花结果,还必须活地更久一点。

当提到 preempt-rt 补丁的时候,我必须强调一点,Linux不是一个裸奔的操作系统。Linux 的应用都是在用户空间写的一个个进程、线程。所以相对于其他 RTOS 可能更加强调高优先级中断的确定性时延(RTOS不太特别强调机制与策略分离的概念,整个东西编译在一起的话,在中断里面放策略也未尝不可),在Linux时间里,用户空间高优先级的 RT 线程的确定性调度时延就显得更加critical(因为Linux内核里面你不能裸奔地把用户策略的东西放进内核,内核提供的是一些操作接口而已,简单来说,你要做的事情是一个应用,而应用是个用户空间的东西)。

风在吼,马在叫,娃儿在咆哮。今天就谈到这里,明天接着谈。我相信你还有很多的疑惑,比如很多童鞋说,你刚才提到的Linux的一些硬实时的毛病,在 RTOS 里面其实也都有,我会给你一个交代。

640?wx_fmt=jpeg

扫码或长按关注

回复「 加群 」进入技术群聊

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

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

相关文章

python 数据分析 实际案例_python实战案例:超市营业额数据分析

实战是学习的最好途径,效率最高,本文不是很长,通过小小的练习,让大家综合运用基础知识,加深印象巩固记忆。一、读入数据,了解数据本数据随机生成的假数据,读者可以自己造,也可以通过…

台达n2系列变频器_台达变频器C2000系列在Profibus网络中的应用

基本介绍现场总线就是顺应信息技术的发展趋势和工业控制系统的分散化、网络化、智能化要求而发展起来的新技术,它的出现和发展已经成为全球工业自动化技术的热点之一,受到全世界和工业界的普遍重视。现场总线(Fieldbus)技术是实现现场级控制设备数字化通…

CentOS 6.8 虚拟机安装详解

第一步:安装 VMware 官方网站:www.vmware.com 下载百度云链接:http://pan.baidu.com/s/1bphDOWv 密码:0zix VMware 是一个虚拟 PC 的软件,可以在现有的操作系统上虚拟出一个新的硬件环境,相当于模拟出一台新…

unittest里discover用法_unittest框架核心要素及应用

1. unittest核心要素unittest介绍测试框架,不仅仅用于单元测试python自动的测试包用法和django.test.TestCase类似1.1【知道】unittest介绍和核心要素1.2【掌握】unittest核心要素的使用""" 1. 测试用例 2. 容器,容器添加测试用例 3. 运行…

void函数调用时显示不允许使用不完整的_4位数码管显示模块驱动

TM1637四位数码管模块是一个带时钟点的4位共阳数码管(0.36英寸)的显示模块,驱动芯片为TM1637,驱动方式为IIC,因此只需2根信号线即可使单片机控制4位8段数码管(数码管8级亮度可调)。模块特点如下:显示器件为4位共阳数码管数码管8级…

在线就能用的Linux我给你找好了

今天的天气真的是超级爽,秋日的凉风吹在脸上真的太美了,好不容易的假期,希望大家都玩得开心,今天分享一篇文章,是守望兄的,总结了几个在线的Linux,喜欢的同学,可以保存下来&#xff…

mysql访问类型最好的_【干货满满】最全的MySQL性能指南(一):选择最佳的数据类型...

对于 MySQL 数据库来说,好的逻辑表和物理表的规划至关重要,我们需要根据查询语句来针对性地设计 Schema ,没有万能好用的 Schema。一个 denormalized 的 schema 可以在某些场景下加速语句查询,但是放在其他应用场景下就会适得其反…

测试两个主机之间的连通性_借助网络测试神器极速解决网络故障

时下,网络使用越来越频繁,随之遇到网络故障的情况也多起来,那么诊断网络故障就成了必不可少的一环,投诉和求助是一种基本的方法,但有时太过缓慢,有些时候自己可以快速搞定,检查到故障原因所在&a…

随想,对嵌入式职场建议

guoqingjie已经过去两天了,因为楠哥生病,我们搁浅在了深圳,不过相比在路上的奔波,待在家里感觉惬意不少,不用在路上各种操心,之前上班感冒,身体处在亚健康状态,睡了两天身体也恢复一…

java可达性_java垃圾回收机制--可达性算法

先说一些题外话,Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区,这些区分为线程私有区和线程共享区1、线程私有区a、程序计数器记录正在执行的虚拟机字节码指令地址。此区域是是唯一一个在java虚拟机规范中没有规定任何Ou…

为什么要有uboot?

一、为什么要有uboot1.1、计算机系统的主要部件(1)计算机系统就是以CPU为核心来运行的系统。典型的计算机系统有:PC机(台式机笔记本)、嵌入式设备(手机、平板电脑、游戏机)、单片机(家用电器像电饭锅、空调…

华为路由器上有没有mac表_MAC地址表、ARP缓存表、路由表及交换机、路由器基本原理...

MAC地址表说到MAC地址表,就不得不说一下交换机的工作原理了,因为交换机是根据MAC地址表转发数据帧的。在交换机中有一张记录着局域网主机MAC地址与交换机接口的对应关系的表,交换机就是根据这张表负责将数据帧传输到指定的主机上的。交换机的…

#define的高级用法

来源:嵌入式大杂烩地址:https://blog.csdn.net/xiaoxu2050/article/details/82893476一、宏的定义与撤销需要注意的是:(1)宏定义应注意添加括号,这样语义会比较清晰。(2)使用#undef可…

python读取csv文件_python3.0读取csv文件

创建CSV文件,可以打开excel文件,创建表格以后,另存为csv文件(以逗号分隔的文件)以文本格式打开,发现是用逗号分隔的用python读取csv文件,首先要引入一个库:csvimport csvdef getCsvFile(strpath):with open(strpath, &…

直击中关村创业大街,新街头霸王来了

中国的硅谷在北京中关村。如今,中关村中正在酝酿硅谷中的硅谷,这里将不断诞生最前卫最现代的互联网和移动互联网创业公司,他们当中极可能孵化出中国互联网企业未来10年的新的BAT。这个硅谷中的硅谷。就是中关村创业大街。这条街在过去15年是北…

我们应该这样理解鸿蒙

之前写过文章谈到的鸿蒙,很多人觉得我说的有点过分,但是我觉得现在出来的情况还是符合预期的,鸿蒙正在完成他的任务。讲个故事,手机还没有普及的时候,相机的地位非常高,相机里面有一个东西叫做胶卷&#xf…

人工智能在语音和数字图像处理领域有哪些具体化应用_智能呼叫中心系统有哪些优势...

近年来,随着科技的发展特别是人工智能技术、云计算、大数据的到来,新技术逐渐渗入人们日常生活中的各行各业里面,以机器人来代替人工处理繁重的任务变得普遍。在人工智能时代下,新一代智能呼叫中心系统应运而生,呼叫中…

centos下mysql多实例安装3306、3307实例(2014-10-15)

背景说明 mysql的安装方法有多种,如二进制安装、源代码编译安装、yum安装等。yum安装仅仅能安装mysql 5.1 版本号;源代码安装编译的过程比較长。若没有对源代码进行改动且要求使用mysql较高版本号,建议使用二进制安装。本文以二进制安装mysql…

如何自己实现一个栈

文章转自编程珠玑,作者:守望先生前言栈是一种应用广泛的数据结构,例如函数的调用就需要使用栈,其实我们在介绍《栈的操作栈的常见操作有出栈(POP),从栈中弹出一个元素;入栈(PUSH),将一个元素压入…

python编写ATM类_Python中编写类的各种技巧和方法

有关 Python 内编写类的各种技巧和方法(构建和初始化、重载操作符、类描述、属性访问控制、自定义序列、反射机制、可调用对象、上下文管理、构建描述符对象、Pickling)。你可以把它当作一个教程,进阶,或者使用参考;我希望它能够成为一份针对…