FreeRTOS学习笔记01

基本概念

  • 操作系统:操作系统是一个用以提供基础计算机功能的计算机程序,它可以向其他程序提供服务,应用来实现用户想要实现的功能。操作系统对应用程序的支持使得开发者在在开发应用程序是更加快捷,简单,易维护。

  • RTOS:大部分操作系统允许多个应用程序同时执行,这种成为多任务。但实际上,在任何一个时间点上只有一个进程在独立执行。由于应用程序切换足够快,好像所有的程序同时执行。操作系统中有一个调度器(Scheduler)的部分负责调度应用程序,决定什么时候执行哪个应用程序,调度器在每个程序之间的切换需要足够快速。实时操作系统费的调度器设计成可以提供确定的执行模式。实时性意味着嵌入式系统对某个具体事件的响应必须严格控制在一个预定的deadline内。实时操作系统会按照排序运行、管理系统资源,并为开发应用程序提供一致的基础。实时操作系统与一般的操作系统相比,最大的特色就是“实时性”,如果有一个任务需要执行,实时操作系统会马上(在较短时间内)执行该任务,不会有较长的延时。这种特性保证了各个任务的及时执行。

  • 线程:线程是操作系统能够进行运算调度的最小单位,包含在进程中,是进程的实际运作单位。一条线程是进程中的一个单一控制流。线程有四枣红基本状态:产生,阻塞,非阻塞,结束。

  • 进程:指计算机已运行的程序,是分时系统的基本运作单位。进程是程序的真正运行实例。进程有五种状态:新生,运行,等待,就绪,结束。在单CPU系统中,任何时间可能有多个进程在等待,但必定仅有一个进程在运行。

  • 线程和进程区别:进程是资源分配的最小单位,线程是CPU调度的最小单位。进程和线程都是一个时间段的描述,是CPU工作时间段的描述,是运行中程序指令的描述。

实时操作系统的设计原则:

  • 实时的消息、事件处理机制:常规的操作系统,消息队列是按照FIFO的方式进行调度。实时操作系统会提供基于优先级的处理方式。
  • 提供内核级的优先级翻转处理方式:实时操作系统调度器最精彩遇到的问题是优先级翻转,因此对于类似信号量一类的API,都能提供抑制优先级翻转的机制,防止操作系统死锁。
  • 减少粗粒度的所和长期关中断的使用:这里的所主要是指自旋锁(Spinlock)一类会影响中断的锁,也包括任何关中断的操作,在Windows和Linux的驱动中,为了同步的需要,可能会长期关闭中断,这里的长期可能是毫秒到百微秒级。但实时操作系统通常不允许长期关中断。对于非实时操作系统来说,如果收到外部中断,系统在处理中断的整个过程中可能会一直关中断。但实时操作系统的通常做法是吧中断作为一个事件通告给另外一个任务,interrupt handler在处理完关键数据以后,立即打开中断,驱动的中断处理程序以一个高优先级任务的方式继续执行。
  • 系统级的服务也要保证实时性:对于一些系统级的服务,如文件系统操作,非实时系统过会缓存用户请求,并不直接把数据写入设备,或者建立一系列线程池,分发文件系统的请求。但是实时系统允许高优先级的任务有限写入数据。这种设计会牺牲性能,但是会保证系统的实时性。
  • 避免提供实时性不确定的API:多数实时操作系统都不支持虚拟内存(page file / swap area),主要原因是缺页中断(page fault)会导致任务调度的不确定性增加。多数实时操作系统过都支持分页,但很少会使用虚拟内存,因为一次缺页中断的开销十分巨大,通常都是毫秒级。会导致用户程序执行的不确定性增加。
  • 提供针对实时系统调度的专用API:
  • 降低系统抖动:由于关中断的原因,通常情况下,操作系统的调度器不会太精确的产生周期性的调度。一个设计优秀的实时操作系统能把抖动降低到微妙甚至是百纳秒级别。
  • 针对实时性设计的SMP和虚拟化技术:

实时性,硬实时,软实时

实时性: 实时性也叫实时计算(real-time computing), 实时约束指的是从事件发生到系统回应之间的最长时间限制。实时程序必须保证在严格时间限制内响应。 换句话说就是,任务(Task)必须在给定的时间(Deadline)内完成。比如汽车安全气囊响应,在汽车检测到撞击后,汽车ECU以及执行器需要在40ms内完全打开气囊,否则就会对乘客安全造成威胁。这个时候就要求汽车ECU的程序运行满足实时性标准。

硬实时: The firm real-time definition allows for infrequently missed deadlines. In these applications the system can survive task failures so long as they are adequately spaced, however the value of the task’s completion drops to zero or becomes impossible.

软实时: The soft real-time definition allows for frequently missed deadlines, and as long as tasks are timely executed their results continue to have value. Completed tasks may have increasing value up to the deadline and decreasing value past it.

区别: 硬实时操作系统必须使任务在确定的时间内完成;软实时操作系统能使绝大多数的任务在确定时间内完成。因此,硬实时和软实时的差别是,软实时只能提供统计意义上的实时。只要任务及时执行就会具有价值,如果任务超出Deadline,只会导致价值的稍微降低。如计算机的声音系统就是软实时的任务。 而硬实时任务只要超时,任务的价值就会降低到零。

任务调度

调度同来确定多任务环境下任务执行的顺序和获得CPU资源后能执行的时间长度。操作系统通过一个调度程序来实现调度功能。调度程序以函数的形式存在,用来实现操作系统的调度算法。调度程序本身并不是一个任务,是一个函数调用,可在内核的各个部分进行调用。调用调度程序的具体位置成为一个调度点(Scheduling point), 调度点通常处于一下位置:**(i)** 中断服务程序的结束位置;**(ii)** 任务因等待资源而处于等待状态;**(iii)** 任务处于就绪状态时。

在操作系统中,一个任务有三种典型状态:

  • 正在运行(Running):正在CPU中执行
  • 待命(Ready):等待执行
  • 阻塞(Blocked):任务暂停,等待一个事件的发生,例如接受一组数据

由于CPU在某个事件只能执行一个任务,因此大部分任务在多数事件处于阻塞或待命状态。可能大量的项目在待命列表里等待执行。这取决于系统所需的任务数量和调度器类型。通常情况下,简单的时间触发式调度器,待命任务列表的数据结构要尽可能缩短最坏情况下,程序在调度器关键部分的执行时间,防止其他任务一直在待命列表中无法及时执行。在这种调度器中,应该尽量避免抢占式任务,甚至应该关闭调度器之外的所有中断。并且待命列表的数据结构应该根据系统所需要最大任务数量进行优化。如果列表任务较多,双向链表是一个合适的结构。在任务列表的排序上,应该按照优先级对任务进行排序。这样可以保证高优先级任务的及时执行。

调度算法:
实时操作系统需要采用各种算法和策略保证系统行为的可预测性,并且调用一切可利用的资源完成实时控制任务。 其实时调度算法分为三种类别:基于优先级的调度算法(Priority-driven scheduling-PD),基于CPU使用比例的共享式调度算法(Share-drivescheduling-SD),基于时间进程的调度算法(Time—driven schedulinq-TD)。

基于优先级的调度算法给每个进程分配一个优先级,在每次进程调度的时候,最高优先级任务首先被执行。算法的类型分为两种:

静态调度:静态调度在系统开始运行前进行调度,严格的静态调度在系统运行时无法对任务重新调度。静态调度的目标是把任务分配给各个处理机,并对每一处立即给出所要运行的静态运行顺序。静态调度算法实现简单

死锁: 死锁是指一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所占用的不会释放的资源而处于的一种永久等待的状态。

死锁的四个条件:

  • 互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用
  • 请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源
  • 非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制的剥夺
  • 循环等待条件(Circular wait):系统中的若干进程组成的环路,该环路中每个进程都在灯带相邻进程正占用的资源

互斥锁: 互斥锁是一种独占锁,当线程A加锁成功后,此时的互斥锁已经被线程A独占了,只要A没有释放受众的锁,线程B加锁就会失败,于是就是会释放CPU让给其他线程,既然B释放了CPU,也就意味着线程B的加锁代码会被阻塞。对于互斥锁加锁失败而阻塞的现象,是由操作系统内核实现的。

自旋锁: 自旋锁是一种特殊的互斥锁,当资源被加锁后,其他线程想要再次加锁,此时该线程不会被阻塞睡眠而是陷入循环等待状态(CPU不能做其他事情),循环检查资源持有者是否已经释放了资源,这样做的好处是减少了线程从睡眠到唤醒的资源消耗,但是会一直占用CPU资源。适用于资源的锁被持有时间段,而又不希望在线程的唤醒上花费太多资源的情况。

  1. 自旋锁为什么不能睡眠?
    因为需要循环检测lock变量。

内存管理

  1. 介绍一下FreeRTOS的内存管理?
  • heap_1:只申请不释放,适用于一旦创建好任务,信号量和队列就再也不会删除的应用。
  • heap_2:最佳匹配,即申请又释放,适用于可能会重复的删除的任务,队列,信号量等应用中,需要注意内存碎片的产生问题。
  • heap_3:简单封装malloc,free,对其进行线程保护。使用时需要编译器提供一个内存堆,编辑器库需要提供malloc()和free()函数。
  • heap_4:最佳匹配+合并相邻内存,具有不确定性,但不会产生严重的内存碎片
  • heap_5:最佳匹配+合并不连续的内存区。
  1. 简述RTOS中,栈空间的最大使用率和栈溢出的检测方法?
  • 方法一:在任务切换时检测任务指针是否越界,如果越界就会在任务切换时触发栈溢出的钩子函数
  • 方法二:在任务创建的时候将任务战所有数据初始化为0Xa5,任务切换进行任务栈检测时检测末尾的16个字节是否都是0xa5,通过这种方式检测栈是否溢出。

参考文章

[1] https://blog.csdn.net/u012993936/article/details/41145863
[2] https://zhuanlan.zhihu.com/p/86861756

作者

John Doe

发布于

2021-05-07

更新于

2021-07-19

许可协议

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

评论