- 任务的独立性表现为逻辑上的
平等性
和信息传输的异步性
。 - 所有任务在逻辑上是平等的。
- 可剥夺型内核意味着
已经就绪的高优先级任务可以剥夺另一个正在运行的低优先级任务的运行权而进入运行状态
。 - 输入/输出设备与
CPU
速度的差别是并发运行的前提和基础,也是一个通常都满足的事实。以CPU
为中心,将与各种输入/输出设备(或端口)相关的功能分别划分为独立的任务。 关键性
是指某种功能在应用系统中的重要性,如果这种功能不能正常实现,则将造成重大影响,甚至引发灾难性的后果。包含关键功能的任务称为关键任务
,关键任务必须得到运行机会,即使遗漏执行一次也不行。对于关键任务,必须尽可能和其他功能剥离,独立成为一个任务,通过通信方式在触发其他任务,完成后续操作。紧迫性
是指某种功能必须在规定的时间内得到运行权(及时运行),并在规定的时间前执行完毕(按时完成),可见这类功能有严格的实时性要求。大多数紧迫任务是由异步事件触发的,这些异步事件一般能够引发某种中断。在这种情况下,将紧迫任务安排在相应的ISR
中是最有效的方法。如果紧迫任务不能安排在ISR
中,那么为它安排在尽可能高的优先级是解决及时性
有效方法。要达到按时完成的目的,必须使紧迫任务需要的执行时间尽可能短。办法是对紧迫任务进行瘦身,尽可能剥离不太紧迫的操作,只剩下必须立刻做的操作,将被剥离的不太紧迫的操作另外封装为一个任务。- 用户应用程序中消耗时机最多的是各种数据处理程序单元,这种单元通常不止一个,它们分别为不同的功能服务。应该将这些单元划分出来,分别包装成为不同的任务。由于这类任务需要消耗较多时机,它们的优先级必须安排得比较低,只使用其他任务剩余的时机来进行数据处理。
- 将关系密切的若干个功能组合成为一个任务,达到功能聚合的效果。
- 如果若干功能由相同的事件触发,则可以将这些功能组合成为一个任务,从而免除将事件分发给多个任务的工作量。符合本类任务的触发条件通常是内部事件。
- 将周期相同的功能组合在一起封装为一个任务,就可以避免一个时间事件触发几个任务,省去事件分发操作和它们之间的通信。
- 将若干按固定顺序执行的功能组合为一个任务,从而免除同步接力通信的麻烦。
- 在用户任务函数中,必须包含至少一次对操作系统服务函数的调用,否则比其优先级低的任务将无法得到运行机会,这是用户任务函数与普通函数的明显区别。
- 采用
创建任务
的方式来启动任务,可以省去用通信手段触发任务的麻烦,还可以通过(* pdata)
来传递原始参数,使得每次启动任务时可以有不同的工作状态。 - 适合采用
创建任务
的方式来启动的任务,通常是孤立任务,它们不和其他任务进行通信(ISR
除外),只使用共享资源来获取信息和输出信息。 - 事件触发执行的任务:此类任务在创建后,虽然可以获得运行权,但任务实体代码的执行需要等待某种事件的发生。相关事件发生一次,该任务实体代码就执行一次。
- 当某个信息的生产者和消费者都是同一个任务(和其他任务无关)时,保存这个信息的数据结构应该在该任务函数的内部定义;当某个信息的生产者和消费者不是同一个任务(包括
ISR
)时,保存这个信息的数据结构应该在任务函数的外部定义,使它成为共享资源,如全局变量。 - 将公共函数设计为
可重入函数
的关键是不使用全局资源;如果可重入函数
调用了其它函数在,则这些被调用的函数也必须是可重入函数
。 - 一个任务的代码设计过程是从上到下的过程,先分析系统总体任务关联图,明确每个任务在系统整体中的位置和角色,再将任务一个一个地进行详细关联分析,然后画出任务的程序流程图,最后按程序流程图编写程序代码。
- 一个任务的运行过程需要和其它任务的运行配合,才能得到预定的效果。任务之间的这种动作配合和协调关系称为
行为同步
。 二值信号量
的使用范围是:被控制方总能及时响应控制方发出的信号,完成相应处理任务,并在下一次信号来到之前进入等待状态。计数信号量
的使用范围是:被控制方不能保证在下次信号来到之前处理完本次控制方发出的信号,但总体上可以响应所有信号。事件标志组
可以实现多个任务(包括ISR
)协同控制一个任务,当各个相关任务(包括ISR
)先后发出自己的信号后(使事件标志组对应标志有效),预定的逻辑运算有效,触发被控制的任务(使其进入就绪状态)。- 由于
消息邮箱
只能存放一条消息,在使用消息邮箱进行同步控制时,必须满足一个前提:任何时候消息的生产速度都比消息的消费速度慢,即被控制任务总是在等待消息,这和二值信号量类似。 消息队列
可以存放多个消息能够有效解决消息的堆积问题。和计数信号量的情况类似,消息队列的使用仍需要满足一个条件:消息的平均生产时间比消息的平均消费时间长(即生产速度慢,消费速度快);否则,再长的消息队列也会溢出。- 可以通过协调生产者和消费者的关系来建立一个产销平衡的理想状态。通信的双方相互制约,生产者通过提供消息来同步消费者,消费者通过回复消息来同步生产者,即生产者必须得到消费者的回复后才能进行下一个消息的生产。这种运行方式称为
双向同步
,它可以达到产销平衡的理想状态。双向同步主要功能为确认每次通信均成功,没有遗漏。 - 事件标志组的
逻辑与
控制功能具有安全控制的特点,它可用来保障一个重要任务必须在万事俱备的前提下才执行;逻辑或
控制功能具有补充控制的特点,它可用来在一个基本控制方式下增加若干补充控制,以满足某些特殊情况的需要。 - 多个任务相互同步可以将若干相关任务的运行频度保持一致(每一轮运行的先后、快慢可以动态变化)。
多任务互相同步
保证在任何情况下各个任务的有效执行次数都相同,而且等于运行速度最低的任务执行次数。这种同步方式具有团队作战的特点,它可以在一个需要多任务配合进行的循环作业中。 - 任务对共享资源进行访问的代码段落成为关键段落,各个任务访问同一共享资源的关键段落必须互斥,才能保障共享资源信息的可靠性和完整性。这种使得不同任务访问共享资源时能够确保共享资源信息可靠和完整的措施称为
资源同步
。 - 当参与访问共享资源的并发程序单元包含
ISR
时,任务级程序单元只能用关中断
的措施来访问共享资源。关中断的优点是简单,缺点是影响任务的实时性。为了减轻对系统实时性的不利影响,访问共享资源的代码必须尽量简短,绝对不允许在关键代码段落中包含有可能使自己挂起的系统服务函数,否则将使系统死机。关中断常用于对全局变量和小规模全局数据结构的访问。 关调度
的缺点是:使与该共享资源无关的任务受到牵连,即使它们的优先级足够高并被ISR
触发到就绪状态也无法运行,而这类与ISR
关联的任务通常有比较高的实时性要求。因此,尽可能不使用关调度的方式。互斥信号
量具有处理优先级反转的功能,特别适合对共享资源的互斥访问。使用互斥信号量来进行共享资源访问对系统实时性影响最小。全局变量
(包括全局数组和全局结构体)可以充当一种共享资源,用来在任务之间传输数据。全局变量虽然可以实现数据传输,但不能实现行为同步。在没有行为同步要求的前提下,当数据的传输量不大时,采用全局变量并搭配关中断的资源同步措施是一种经济有效的方法。消息邮箱
就是具有行为同步功能的通信手段,当双方的执行频度相同时,消息邮箱
是合适的通信工具。如果用ISR
的局部变量来保存消息,接收消息的一方就不能获得真正的消息。原因是接收消息的一方在获得消息指针时ISR
已经结束,它的局部变量也一同消失。ISR
可靠发送消息的方法有三种:将消息保存在全局变量中;将消息保存在ISR
的静态局部变量中;将消息的内容冒充指针进行发送。冒充指针进行发送的方法如下所示:对发送方,如果消息指针的格式改为(void *)Temp
,则将变量Temp
的数值(而不是地址)作为消息指针执行传输;对接收方,当指针消息为短消息时,不再把它当做指针看待,而应该通过强制类型转换(u32
),直接当做一个4
字节的整数使用。消息队列
适用于以下场合:通信双方至少有一方没有稳定的执行周期;通信双方的执行周期不同。要使用消息队列,需要准备两个数组:一个是消息指针数组,供实时操作系统用来排队使用;另一个是消息内容数组,供用户使用。使用消息队列的最简单方法是利用实时操作系统的动态内存管理功能来管理消息内容数组。如果发往消息队列的消息全都是内容比较简短(不超过4
字节)的短消息,就可以省略消息内容数组,这给我们带来不少方便。- 时间管理函数只能用在对时间精度要求不高的场合,或者时间间隔较长的场合。
- 查询过程是一个无限循环的过程,只有当希望的状态出现以后才能退出这个无限循环,这种情况在实时操作系统中是不允许的,它将剥夺低优先级任务的运行机会。解决这个问题的办法是
用定时查询代替连续查询
,即在查询的过程中插入系统延时函数,不断地将CPU
交出来,供其他任务使用。 - 调用
有超时限制的等待信号量(或消息)
的系统函数可以实现双重目的:在没有按时获取信号量(或消息)时,其超时效果起到了控制运行周期的作用(与系统延时函数相同);当成功获得信号量(或消息)时,可以及时退出循环,终止周期性任务。 - 当采样对象是一个低频信号时,采样频率可以设置得比较低,即采样周期比系统节拍周期长得多,将采样周期设置为系统节拍的整数倍,就可以用系统提供的延时函数来控制采样周期。这样,采样功能就可以由一个独立的采样任务来完成,而不需要
ISR
配合;当采样周期与系统节拍在同一数量级时,可以另外使用一个定时器,由定时器中断产生稳定的采样周期。 - 当某种功能的运行周期与系统节拍相同时,使用系统节拍函数的钩子函数来完成此项功能是非常有利的。
系统节拍钩子函数
是系统节拍函数的一部分,具有ISR
的性质,应当尽可能简洁,不允许调用任何可能使自己挂起来的系统服务函数。 - 由外部信号启动采样过程的方式称为
被动采样
。在被动采样中,启动采样的时刻是随机的,故没有采样周期的概念。 - 对于串行通信任务设计,有两种情况会使接收过程出现差错:
- 系统关中断的最长时间大于相邻两次串行接收中断的间隔时间,这时有可能遗漏一次中断,造成数据丢失。
- 有一个比串口中断优先级更高的
ISR
,其运行期间即时将中断打开,串口中断也不能响应;如果高优先级ISR
的运行时间比相邻两次串行接收中断的间隔时间长,同样有可能遗漏一次中断,造成数据丢失。
要想可靠地接收数据,需要满足以下条件:
- 相邻两次串行接收中断的间隔时间必须大于系统死区时间。
- 接收缓存区的空闲时间必须足够存放在死区时间内接收到的新数据。
数据发送为主动任务,没有什么风险。当一帧数据需要分若干次发送时,由于实时操作系统的介入,串行发送任务不宜采用查询的方法完成发送任务,以免浪费宝贵的CPU
资源,最好由ISR
和串行发送任务配合完成。