嵌入式中的操作系统知识
sysfs
可以理解为Linux内核把设备、驱动以及部分内核对象,以目录和文件的形式呈现给用户空间的一套接口
通常挂载在
/sys
- 这里的文件大多不存放在硬盘中,而是内核根据当前的状态生成的
为什么需要sysfs?
Linux内核管理大量对象:
- CPU
- 内存
- 磁盘
- 网卡
- USB设备
- PCI设备
等等…
用户空间的程序需要知道:
- 当前有那些设备
- 某个设备使用什么驱动
- 设备属于那条总线
等等…
如果每一种设备都设计一套专用接口,系统会非常混乱,因此通过sysfs,把许多内核对象统一映射成目录和属性文件
他不是真正的磁盘文件系统
可以检查/sys的文件系统类型
findmnt /sys
通常会看到
TARGET SOURCE FSTYPE OPTIONS
/sys sysfs sysfs rw,nosuid,nodev,noexec,relatime
这里的sysfs是一种虚拟文件系统
读取/sys中的文件->进入内核对应的读取函数->内核动态返回读取函数
写入也是如此
写入/sys中的文件->进入内核或者驱动的处理函数->修改设备或者内核状态
因此
- 文件内容通常由内核实时生成
- 不占用普通磁盘空间
- 设备消失后,对应目录也可能立即消失
- 重启之后手动写入的配置通常不会保留
- 某些文件即使显示可写,也可能因为硬件或者内核限制而写入失败
硬实时系统和软实时系统
软实时系统:
- Windows Linux系统通常为软实时
硬实时系统:
- 对时间要求很高,限定时间内不管做没做完必须返回,比如:FreeRROS RT-thread
非实时操作系统和实时操作系统的区别和选择
非实时操作系统和实时操作系统的核心区别,不是谁的运行速度更快,而是能不能保证任务在规定时间内得到响应并完成
- 非实时操作系统比如Windows Android,主要追求吞吐量,功能完整性和用户体验,他的任务调度,内存管理、驱动、后台服务都会引入不确定延迟,所以通常只能保证“尽快处理”,不能严格保证某个任务一定在规定时间内完成
- 实时操作系统,比如:FreeRTOS、RT-Thread,主要追求的是任务响应的确定性。支持优先级抢占调度,能够让高优先级任务及时运行,并且尽量控制中断延迟、任务切换延迟和资源访问的时间
RTOS一般具有以下的特点:
- 1、任务按照优先级调度,高优先级的任务可以抢占低优先级
- 2、中断响应和任务切换延迟比较可预测
- 3、内核较小,适合内存和CPU资源有限的MCU
- 4、通常不使用复杂的虚拟内存和换页机制,减少不可预测延迟
- 5、需要注意优先级反转、死锁、临界区过长、动态内存碎片等问题
选择
如果是普通应用、服务器、图形界面、数据库、复杂网络服务,通常选择Linux或Windows,因为他们功能丰富、驱动和第三方库多,开发效率高
如果项目需要严格的实时响应,比如:电机控制、机器人控制、无人机飞控等,通常选择RTOS,或者是裸机加简单调度器
==注意:==在更复杂的项目中,也可采用混合架构,Linux负责界面、网络、文件系统和数据处理,RTOS负责电机、传感器、安全控制。两者通过消息队列、共享内存或者通讯总线交互
互斥锁 消息队列 信号量
互斥锁 厕所只有一把钥匙
假设系统里面有一个串口,多个任务都可能打印
任务A:printf("hello")
任务B:printf("world")
如果两个任务同时使用串口,输出可能变成:
hewoolrld
这个时候就需要互斥锁
使用的过程
xSemaphoreTake(uartMutex, portMAX_DELAY);
printf("hello");
xSemaphoreGive(uartMutex);
意思是:
- 先拿到钥匙
- 拿到了才能使用串口
- 用完归还钥匙
- 其他任务继续排队
互斥锁的特点
互斥锁有“主人”概念
任务A拿的锁,应该由任务A释放
此外,Mutex通常支持优先级继承
低优先级任务拿着锁
高优先级的任务正在等这个锁
系统会暂时提高优先级任务的优先级
这样可以避免优先级任务被低优先级任务卡太久,这叫优先级反转保护
什么时候不要使用Mutex?
不要用Mutex表示“某个中断发生了”或者“某个任务完成了”
比如:
DMA完成了,通知任务处理数据
这种情况应该使用二值信号量、任务通知或者队列
消息队列Queue:传送带上的包裹
一个任务把数据放进去,另一个任务取出来
例如按键任务检测后,把按键值放入队列:
uint8_t key = 1;
xQueueSend(keyQueue,&key,portMAX_DELAY);
显示任务从队列读取:
uint8_t key;
if (xQueueReceive(keyQueue, &key, portMAX_DELAY) == pdPASS) {
process_key(key);
}
消息队列的特点:
-
队列可以存很多条信息
-
xQueueCreate(10,sizeof(Message)); -
最多可暂存10条消息
-
-
队列会复制数据
-
xQueueSend(queue,&message,timeout); -
FreeRTOS会把message的内容复制到队列中
-
-
队列满了
- 立即返回失败
- 等待一段时间
- 一直等到有空位
什么时候使用消息队列
当你需要传递“具体数据”时,优先考虑队列
信号量:敲门通知
信号量更像是“通知”或者“计数器”
它通常不关心具体数据,只关心:
事情发生了没有
现在有几个资源
信号量主要分为三种常见的形式
- 二值信号量
- 计数信号量
- 互斥锁
二值信号量
只有两种状态
0:没有通知
1:有通知
计数信号量
统计还有几个
计数信号量不是只有1和0
适合统计空闲缓冲区数据、限制同时运行的任务数、管理多个相同硬件资源等等
| 类型 | 主要作用 | 是否传递数据 | 是否有持有者 | 常见场景 |
|---|---|---|---|---|
| Mutex | 保护共享资源 | 否 | 有 | 保护串口、共享变量 |
| 二值信号量 | 发送一次通知 | 否 | 没有严格持有者 | 中断通知任务 |
| 计数信号量 | 统计资源或事件数量 | 否 | 没有严格持有者 | 缓冲区、资源池 |
| 消息队列 | 传递数据 | 是 | 不适用 | 命令、传感器数据 |
口诀:
Mutex:这个东西一次只能一个人用
Queue:我有一条数据要交给你
Binary Semaphore:有事情发生了,快来处理
Counting Semaphore:现在还有几个资源
Task Notification:直接提醒某个任务
互斥锁是钥匙;
消息队列是传送带;
二值信号量是敲门;
计数信号量是库存表;
任务通知是打电话。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐
所有评论(0)