在这里插入图片描述

摘要

实时操作系统 (RTOS) 和操作系统 (OS) 都提供了设置线程优先级的功能,我们会依据软件功能架构划分情况,为每个线程分配唯一的优先级,从而在系统中创建线程的层次结构。然而,这种线程优先级分配原则会产生问题,为每个线程分配唯一的优先级可能会影响延迟、响应速度、死锁和 CPU 利用率,从而引发问题。

可视化线程分析请参考另外一篇文章系统级调试利器SystemView移植及使用教程

优先级的核心理解

优先级是一种衡量线程在“响应延迟的确定性”的指标,RTOS需要一个线程运行时,该线程可能不会立即进行响应,因为其他线程或者中断的影响,可能会延迟一段时间才运行。
优先级越低,从需求响应到实际响应中间,夹杂的事件越多,事件链路复杂性越高,延时的可分析性和可预测性越差;
优先级越高,它被意外事件干扰的概率越低,延迟性的可预测性越高,系统中最高优先级的线程的延迟是最容易预测的,因为该线程的延迟性几乎是恒定不变的,只有一些细微的中断事件会影响其抢占CPU,没办法,谁让人家是最高级线程;

线程优先级的初始分配

中断相关线程(事件类型)

首先,说明一下中断服务的组成:

  • 中断延迟,中断请求到中断服务的时间 (中断屏蔽+中断嵌套+Sbus压栈(包含总线竞争)+向量表加载)
  • 中断前部分,ISR,需要快速处理的关键部分,即ISR服务函数,
  • 中断后部分,开中断环境下,在ISR外的用户任务中处理的部分
    中断相关线程用来完成中断后半部分工作内容,中断事件一般都是较为紧急的事件,在功能性上和中断服务有交集的任务,都需要分配较高的任务等级,一般不会设置周期性的调度,而是采用事件通知性的调度,中断事件发生且完成后,使用信号量、队列、任务通知等机制激活任务运行。例如,UI交互式任务和通讯中断相关,必须设置较高等级,快速响应UI界面操作,接收到UART完整数据后,使用队列发送给任务,激活任务运行。
  • 近高原则:在功能上和中断服务距离越近,线程等级就越高,以及时响应中断
  • 次近高原则:功能上,和中断服务之间夹杂了一个或少量的任务(一般为1~3个),可以设置稍微较低优先级,但需要使用资源锁机制,在关键时候进行优先级穿透,以处理次级中断事件相关内容。
    在这里插入图片描述
    在这里插入图片描述

周期类型线程

需要按照固定频率去运行的任务,从软件需求、系统方案、详细设计中获取相关功能的运行指标:吐屯量需求、最大延迟时间、平均执行时间、最大执行时间等。例如:

  • LED屏幕的刷新速率需要不低于60FPS,最高不超过120FPS
  • 电机的PID控制算法需要每3ms计算一次
  • 看门狗安全线程最慢需要每秒一次喂狗
  • CPU使用率不可超过50%
    当系统负载不超过约69.3%时,所有任务都可以按时完成(参考Scheduling Algorithms for Multiprogramming in a Hard Real-Time Environment)。一般,周期越短的任务被赋予越高的优先级。

线程优先级的后续调整

何时才需要真正的去修改它们的优先级呢?

关键原则:

  • 延迟不满足才进行抢占
    当延迟超过需求的吞吐量,并且绝对需要抢占时,才使用不同的优先级,在任何其他情况下都不要使用任务抢占机制。例如,需要满足关键的实时截止期限,线程A和线程D具有类似的工作内容,但要求线程A在收到消息时能立刻运行,那A的优先级就必须要比D要高。
  • 少用不同优先级
    使用尽可能少的不同优先级,并为需要真正抢占的情况保留唯一的优先级。
  • 模糊时使用同等优先级
    如果无法比较出两个或多个任务的优先级高低时,使用同等优先级使用同等优先级,使用时间片的方法使任务依次运行,使任务“公平运行”,防止任务饥饿问题产生。
    可以避免不合理的上下文切换,减少RTOS开销(注意:是不合理的开销,不是说总量就比不同优先级的开销低,相反,这种总体开销更高,因为基本不会产生任务饥饿)。
  • 牵一发动全身
    另外,必须要注意,当前各个线程的优先级调整好后,如何再加入新的线程,可能会扰乱所有线程的优先级顺序,可谓牵一发动全身。
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐