使用RTOS,可以很容易地将应用代码分成更小的相互独立的任务。但实际应用中,几乎不可能拥有完全独立的任务。许多情况下,任务需要特定的外部事件激活,例如,来自中断服务程序或另一个任务的服务请求。在这种情况下,任务通常需要接收相关参数输入。此外,任务经常需要共享硬件资源,如一次只能由一个任务使用的通信接口。
多任务系统中,任务之间的交互行为是否符合设计要求?今天我们来了解一下如何使用Tracealyzer工具辅助查看任务之间的交互行为,判断系统行为的正确性。
任务交互
多任务系统中,任务之间的交互包括同步和通信服务。常用的同步对象如下:
信号量
任务/中断之间的信号不需携带数据时,可以使用信号量实现同步。信号的含义由信号量对象说明,最常见的信号量类型是二值信号量,用于触发任务活动。典型的设计是任务包含一个无限循环,调用RTOS服务以获取信号量。如果信号量尚未发出信号,RTOS将阻塞任务执行,直到某个任务或中断给出信号量。
互斥信号量
实现互斥操作的二值信号量,用于保护临界区,实现任务之间的互斥操作。其工作原理与二值信号量相同,但使用方式不同。它在进入临界区之前先获取信号量,使用完成之后立即释放信号量。互斥信号量会记录其所有者(任务),并可能修改任务的调度优先级以避免“优先级倒置”的问题。
队列
队列是一个FIFO缓冲区,将消息传递给任务。通常,每个队列只有一个接收者,可以有一个或多个发送者。队列通常用作服务类型任务的输入,提供多种服务/命令。
RTOS 通过提供多种类型的交互机制,用于任务之间、中断和任务之间的通信和同步。图1中,任务H阻塞直到互斥信号量(mutex)可用,因为互斥信号量通常只用于临界段,持续时间比较短,所以实现本身没有问题。
图1 优先级反转
优先级继承然而,不相关的中等优先级任务M会抢占任务L,如图1所示,从而延迟了互斥信号量的释放时间,导致任务H可能会阻塞很长时间,这种现象称为优先级倒置或反转。原则上,实时系统中高优先级的任务不应该被低优先级任务阻塞。但在实际应用中,设计可能导致这种优先级反转情况发生。
优先级倒置意味着高优先级任务会被较低优先级任务意外延迟。大多数RTOS为互斥信号量提供优先继承机制,在更高优先级的任务因为无法获取互斥信号量而阻塞时,临时提升其所有者任务的优先级,避免中等优先级任务的干扰。优先级倒置也可能发生在队列原语中。
使用Tracealyzer可视化任务交互
通过Tracealyzer,可以查看应用中的RTOS调用,包括对队列、信号量和互斥信号操作,在主跟踪视图的垂直时间轴上,与任务调度、中断和记录的应用事件一起显示,参见图2。
图2 Tracealyzer主视图中的RTOS调用显示
在主跟踪视图单击信号量、队列或互斥信号量事件,可以打开选定对象的内核对象调用历史视图,如图3所示,视图显示了指定对象的所有操作和状态随时间的变化。在此视图中双击事件可以在主跟踪视图中找到对应的事件。
对于队列对象,你还可以直观地看到任何时候缓冲区中的消息数量,跟踪消息的发送到接收的过程。对于互斥信号量,还可以看到其所有者任务的名称。
图3 对象历史视图
Tracealyzer 还提供了任务和中断之间通过内核对象相互作用的通信流图。图 4显示了一个示例,矩形框表示任务和中断,而椭圆表示队列或信号量。
图4
通信流视图直观的展示了消息是如何在应用程序内传递的,可以作为分析任务交互调试的开始。
多任务应用中,源代码本身并不能完全描述系统在运行时的实际行为,如多任务应用中的资源共享异常,难以依靠单独的源码分析来发现。通过Tracealyzer辅助分析,查看实时应用中通信流是否符合设计,信号量、队列等内核对象的状态变化是否符合预期,从而帮助解决错误,提高整体软件质量并减少故障排除时间。