
“任务和计划”一文中考虑了RTOS计划者工作的基本原则。 在本文中,我们将详细介绍Nucleus RTOS提供的功能以及Nucleus SE提供的功能。
该系列中的先前文章:
第8条 Nucleus SE:内部设计和部署
第7条 Nucleus SE:简介
第6条。 其他RTOS服务
第5条 任务交互和同步
第4条 任务,上下文切换和中断
第3条 任务与计划
第2条。 RTOS:结构和实时模式
第1条 RTOS:简介。
在Nucleus RTOS上进行规划
由于Nucleus RTOS是成熟的,功能完善的商业RTOS,因此我们可以放心地假定调度程序是根据此类产品的要求开发的。 这个复杂而灵活的操作系统为开发人员提供了广泛的功能,可以解决几乎所有可能的实时编程任务。
调度程序可以支持无限数量的任务(仅受可用资源限制),并可以与优先级管理一起使用。 可以为任务分配0到255之间的优先级,其中0是最高优先级,而255是最低优先级。 任务具有动态优先级,也就是说,可以在运行时由任务本身或其他任务更改它。 可以为多个任务分配相同的优先级。 在极端情况下,可以为所有任务分配相同的优先级,这使得可以根据循环和时间片原则实施计划策略。
如果有多个具有相同优先级的任务,则将使用Round Robin算法按照准备的顺序对其进行调度。 该任务需要暂停或转移控制权,以便下一个任务开始。 还可以为任务分配时间间隔,以便更有效地控制可用处理器时间。
任务计划是100%确定性的,这在相似的核心中是可以预期的。 任务也可以动态创建和销毁,这要归功于调度程序,用户不会注意到它的发生。
在Nucleus SE进行规划
我已经开发了Nucleus SE的所有方面,以便它们通常与Nucleus RTOS兼容,但在内存方面也更简单,更高效。 调度程序也不例外。 它提供了Nucleus RTOS Scheduler的许多功能,但有所限制。 通过组装过程中的配置可实现灵活性。
Nucleus SE应用程序最多可以执行16个任务(至少一个)。 尽管理论上可以增加这个数目,但是算法的效率将受到威胁; 许多数据结构依赖于将任务索引号(从0到15)存储在半字节(四位)中,并且它们将需要与相应的代码一起处理。
为了在灵活性和简单性(和大小)之间取得平衡,Nucleus SE不再提供一种具有多种功能的调度程序,而是提供了四种调度程序中的一种来进行选择:运行到组件(RTC),循环调度(RR),时间片( TS)和优先级。 调度程序是在组装时静态选择的。 有关每种类型的调度程序的详细信息,请参见下面的“调度程序类型”部分。
像Nucleus SE的任何其他方面一样,任务是静态对象。 它们是在配置期间确定的,其优先级(索引)无法更改。
Nucleus SE规划师
如上所述,Nucleus SE提供了四种类型的调度程序之一供您选择。 与Nucleus SE配置的大多数方面一样,此选择是通过写入nuse_config.h来确定的,必须相应地设置NUSE_SCHEDULER_TYPE参数,如配置文件中的以下片段所示:

无论选择哪个调度程序,在系统初始化后都会立即调用其启动代码。 下一篇文章将提供有关初始化Nucleus SE的完整信息。
运行完成计划程序
如果满足应用程序的要求,则RTC Scheduler是最简单,最合适的解决方案。 每个任务必须先完成其工作,然后才能执行返回功能并允许调度程序完成下一个任务。
每个任务都不需要单独的堆栈。 所有代码都是用C编写的,不需要汇编语言。 以下是完整的RTC调度程序代码。

代码只是一个无限循环,需要轮流调用每个任务。 NUSE_Task_Start_Address []数组包含指向每个任务的外部函数的指针。 PF0宏是将void指针简单地转换为没有参数的void函数的指针的转换。 它旨在确保代码的可读性。
条件编译用于启用对其他功能的支持: NUSE_SUSPEND_ENABLE确定是否可以挂起任务; NUSE_SCHEDULE_COUNT_SUPPORT确定每次计划任务时是否需要计数器值。 可以在下一篇文章中找到关于此的更多信息。
调度程序循环
如果需要的灵活性比RTC调度程序提供的灵活性高,则RR调度程序是合适的。 它允许任务转移控制权或暂停,然后从同一点继续。 除了代码复杂性和不可移植性之外,其他额外开销是每个任务都需要自己的堆栈。
调度程序代码由两部分组成。 启动组件如下:

如果启用了对任务初始状态的支持(使用NUSE_INITIAL_TASK_STATE_SUPPOR T参数,请参阅下一篇文章中的“参数”),则计划从第一个完成的任务开始; 否则,将使用索引为0的任务,然后使用NUSE_Context_Load()加载此任务的上下文。 有关保存和还原上下文的更多信息,请参见下一篇文章中的“保存上下文”部分。
计划程序的第二部分是“重新计划”组件:

当任务释放中央处理器或暂停时,将调用此代码。
该代码选择要启动以下索引的任务,并将该值放在NUSE_Task_Next中,同时考虑是否启用了任务挂起。 然后,使用NUSE_CONTEXT_SWAP()宏使用软件中断来调用上下文切换。 有关保存和还原上下文的更多信息,请参见下一篇文章中的“保存上下文”部分。
优先调度器
与其他选项一样,Nucleus SE中的Priority Scheduler旨在提供所需的功能,同时非常简单。 结果,每个任务都具有唯一的优先级,不可能有一个优先级来执行多个任务。 优先级由任务的索引确定,其中0是最高优先级。 任务的索引由其在NUSE_Task_Start_Address []数组中的位置确定。 下一篇文章将提供有关设置任务的更多详细信息。
像RR和TS调度程序一样,优先级调度程序具有两个组件。 优先级调度程序的启动组件与RR和TS调度程序相同,如上所述。 重新安排组件略有不同:

没有任何条件代码可以禁用任务的挂起,因为此功能对于优先级调度程序是必需的。 任何其他选择都是不合逻辑的。 NUSE_Reschedule()函数接受一个“告诉”下一个可以计划的任务的参数-new_task。 调用重新计划时会设置此值,因为调用了另一个任务。 该任务的索引作为参数传递。 然后,调度程序可以通过比较new_task的值与当前任务的索引(NUSE_Task_Active)来确定是否执行上下文切换。 如果重新计划是任务暂停的结果,则参数将设置为NUSE_NO_TASK ,并且计划程序将搜索优先级最高的任务。
任务状态
通常,所有操作系统都具有在特定“状态”下查找任务的概念。 详细信息取决于RTOS。 在本文中,我们将研究Nucleus RTOS和Nucleus SE如何使用任务状态。
Nucleus RTOS任务状态
Nucleus RTOS支持5个任务状态。
- 执行:当前管理处理器的任务。 显然,只有一个任务可以占据此状态。
- 准备就绪:在计划者决定启动任务之前已准备好执行(或继续执行)的任务。 通常,一项任务的优先级低于正在执行的任务。
- 暂停:“睡觉”任务。 在计划中直到唤醒它才将其考虑在内,届时它将“准备就绪”并可能在以后继续执行。 通常,一个任务处于“睡眠”状态是因为它正在等待某些东西:当资源变为可用时,设置的时间段到期时或其他任务将其唤醒时。
- 取消:任务被“杀死”。 在计划中直到重置后才考虑它,此后任务将“准备就绪”或“暂停”。
- 结束:只需离开外部单元或执行return语句,任务就完成并退出其外部功能。 在计划中直到重置后才考虑它,此后任务将“准备就绪”或“暂停”。
由于Nucleus RTOS支持动态创建和销毁对象(包括任务),因此也可以将任务视为“远程”状态。 但是,由于任务一经删除,其所有系统资源就会不复存在,并且任务本身不再存在,因此无法具有状态。 任务代码可能可用,但是必须重新创建任务对象。
Nucleus SE中的任务状态
Nucleus SE中的任务状态模型要简单一些。 通常只有三种状态:执行,可用性和暂停。 每个任务的状态存储在
NUSE_Task_Status []中 ,其值的类型为
NUSE_READY ,尽管它永远不会具有反映执行状态的值。 如果未启用任务挂起(请参阅下一篇文章中的“选项”),则只能有两个任务状态,并且此数组不存在。
有几种类型的暂停任务。 如果一个任务是由其本身或由另一个任务显式挂起的,则称为“纯挂起”,并以状态NUSE_PURE_SUSPEND表示。 如果“睡眠”状态为打开并且任务被暂停了一段时间,则其状态为
NUSE_SLEEP_SUSPEND 。 如果启用了阻止API调用的功能(通过
NUSE_BLOCKING_ENABLE ,请参阅下一篇文章中的“参数”),则任务可以挂起,直到资源可用为止。 每种类型的对象都有其自己的任务挂起状态,例如,以
NUSE_MAILBOX_SUSPEND的形式
。 在Nucleus SE中,可以将任务锁定在内存分区,事件组,邮箱,队列,通道或信号量中。
线程状态
在讨论任务行为时,通常非常自由地使用“状态”和“状态”一词。 还有一个附加因素,可以有条件地称为“流动状态”。 这是全局变量
NUSE_Thread_State,其中包含正在执行的代码的性质的指示。 这适用于许多API调用的行为。 可能的值:
- NUSE_TASK_CONTEXT -API调用是从任务进行的。
- NUSE_STARTUP_CONTEXT-通过启动代码进行API调用; 调度程序尚未启动。
- NUSE_NISR_CONTEXT和NUSE_MISR_CONTEXT -API调用是从中断处理程序进行的。 Nucleus SE中的中断将在下一篇文章中讨论。
下一篇文章将详细介绍Nucleus SE中的高级调度程序功能以及维护上下文。
关于作者: Colin Walls在电子行业工作了30多年,大部分时间用于固件。 他现在是Mentor Embedded(Mentor Graphics的一个部门)的固件工程师。 Colin Walls经常在会议和研讨会上发表演讲,他撰写了许多技术文章并撰写了两本有关固件的书。 居住在英国。
Colin的专业
博客 ,电子邮件:colin_walls@mentor.com