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:直接提醒某个任务

互斥锁是钥匙;
消息队列是传送带;
二值信号量是敲门;
计数信号量是库存表;
任务通知是打电话。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐