Hi, 在本节课时中,我们学习怎样创建一个任务。

如果你阅读过一些RTOS的文档,想必可以看到文档的最开始部分首先会介绍怎样用其API去创建任务。因为只有去创建任务后,才能够去做具体工作,才有机会使用RTOS的其它功能模块。 本课时将以tinyOS为例,介绍如何去创建任务。但是在课程中我们的重点不在于去了解API,而是去了解创建任务需要什么,应该如何安排任务的创建流程。这就是这门课不同于API手册之处。

主要内容

划分任务

通常情况下,我们会根据功能的划分创建相应的任务去完成这些功能
创建任务并运行起来 - 图1
在划分具体的功能时,功能可大可小,具体取决于很多因素。但是,考虑到系统资源有限,我们不可能创建太多任务,所以有时候可能将多个任务合并交给某一个任务处理。
根据任务执行的功能重要性、处理的事件紧急程度不同,可以给任务划分不同的优先级。

任务的表现

在课程中,我们介绍了RTOS的具体表现形式,以及其内在状态。
创建任务并运行起来 - 图2
对于上图,不仅是我们课程中所用的tinyOS符合。如果你去看uCOS、RTX等,可以任务的表现形式基本上符合上图,只是在细节上略有差别。
大部分情况下,任务的表现形式都如上图所示,是一个死循环的函数。这是因为这些RTOS通常运行于资源有限的芯片上,没有必要支持多进程,所以其表现形式类似于PC机上的多线程。

任务数据结构及组织

为了表述任务,RTOS中通常会用一个特定的数据结构(不同OS取名不同),来保存任务运行的各个状态/配置。
创建任务并运行起来 - 图3
然后,在内核中会通过链表、位图等某些数据结构将这些任务结构按照一定策略组织起来。

任务的创建

不同OS创建任务的API接口不同,但是主要的几个关键参数都是相同的。这些关键参数决定了任务执行什么功能,在什么样的环境下,以什么样的优先级去执行。
创建任务并运行起来 - 图4

任务创建与启动流程

在课程中,我们着重讲解了不同的任务启动流程。
创建任务并运行起来 - 图5

方案一和方案二各有优缺点。但是相比之下,方案一可以避免方案二的潜在问题:在系统还没跑起来时,初始化硬件产生中断,导致中断服务程序中如果调用了OS相关接口,导致整个OS挂掉。方案一的优势在于:在初始任务跑起来之前,操作的只是内存数据(初始化、读写)、只有一个执行流(不可能发生中断,也没有任务),所以整个系统状态完全可控,不会发生异常情况。

重点难点

任务创建与启动流程

本课程中重点在于任务的创建与启动流程。
很多RTOS只是提供了相应的接口,然后将由你自己在main()中调用相应的接口初始化整个系统、初始化相关数据、创建任务;控制权完全在你手里。
例如ucos提供了OSInit()、OSStart()接口,放在main()中初始化系统并启动内核。两个接口调用之间,你可以随意插入各种信号量创建、任务创建等操作。
也有的os直接定好了初始化流程,你只能在特定的点插入信号量创建、任务创建等操作。
在实际使用过程中,请根据所用的os提供的接口,完成代码的编写。但无论是使用的哪种类型的OS,都要注意在视频中所提到的问题。

注意事项

任务的启动

有的系统在创建任务之后,如果当前该任务优先级最高,会立即切换到该任务。
但也有的系统创建任务之后,即使是该任务优先级最高,也不会立即尝试切换到该,而是需要你手动再调用相关的接口去告诉内核进行一次任务调度。
在实际使用时,要注意这点。不然,如果遇到第二种情况,你可能会发现任务创建后却不立即运行的诡异现像,而是等好长一段时间候才运行(有其它任务/中断触发了任务调度)。:)

常见问题