1. 任务与多任务

多任务环境允许实时应用程序由一系列独立的任务构成,这些任务拥有自己的执行与系统资源。

2. VxWorks系统任务

根据具体的配置,VxWorks在启动时将运行各种系统任务,其中有些任务会一直运行。

VxWorks基础任务如下:

VxWorks 7 Multiply Tasks

VxWorks 7 Multiply Tasks

VxWorks 7 Multiply Tasks

可选组件任务如下:

VxWorks 7 Multiply Tasks

VxWorks 7 Multiply Tasks

VxWorks 7 Multiply Tasks

3. 任务拥有权与继承属性

根用户是所有任务和RTP的默认拥有者。可以使用如下函数了解任务拥有权与继承属性:

  • getuid()
  • getgid()
  • setuid()
  • setgid()
  • taskShow()
  • ps -l (用于RTP)

4. 任务状态和转换

下表描述了在开发工具中课件的任务状态和状态符号。需要注意的是,任务状态是可以累加的,同一时刻一个任务可能处于多个状态下。

VxWorks 7 Multiply Tasks

Shell命令行中的任务状态示例

VxWorks 7 Multiply Tasks

基本的任务状态转换图示

下图展示了基本的任务状态转换关系。为了简化关系,图中没有展示上述的叠加状态,也没有展示STOP状态。

注意:taskSpawn()函数将创建一个任务,并使之进入Ready状态;taskCreate()函数将创建一个任务,并使之进入suspend状态。

VxWorks 7 Multiply Tasks

5. 任务调度

多任务环境需要任务调度器将CPU分配给处于ready状态的任务。VxWorks提供了多种调度器选项:

  • 传统VxWorks调度器,提供基于优先级的抢占调度,具备round-robin扩展;
  • VxWorks POSIX线程调度器,用于运行进程中的线程(RTP)
  • RTP分时调度器,允许按照时间片调度RTP;
  • 自定义调度器框架,允许自定义开发调度器;

任务优先级

任务优先级在创建时指定,任务调度器依赖于优先级进行调度。VxWorks内核提供了256个优先级,最高优先级为0,最低优先级为255。

内核应用程序优先级

所有应用程序应该运行在优先级100~255。

注意:网络应用程序任务的优先级可能需要运行在低于100的优先级下。

驱动程序的任务优先级

驱动任务优先级范围为51~99。

任务倒置:将一个内核任务移动到优先级队列的队尾

可使用函数taskRotate()实现该功能,结合该函数可以间接实现round-robin机制。

6. 任务创建与激活

taskLib库中提供了创建、控制任务的函数,也提供了获取任务信息的函数。如下所示:

VxWorks 7 Multiply Tasks

7. 任务名称与ID

taskLib中提供的任务名称和ID函数如下所示:

VxWorks 7 Multiply Tasks

8. 任务选项

9. 任务栈

任务的栈空间是在任务创建时定义的。可以使用guard zone使任务栈不可执行,从而对任务栈进行保护。

想要确切知道一个任务需要多大栈空间是很困难的。为了避免栈溢出与崩溃,可以在分配任务栈时分配一个比预期大小更大的空间。之后可以使用checkStack()函数或ti()函数周期性地检查任务栈。当确认了具体的使用情况后,可以调整栈大小以适应测试或系统部署的要求。

任务栈保护

可以使用guard zone通过将任务栈设置为不可执行,来实现任务栈保护。

任务栈guard zone

通过配置INCLUDE_PROTECT_TASK_STACK组件,可以为任务使能guard zone保护功能。如果对系统内存要求比较严格,后续在进行最终测试或系统部署时可以移除该组件。

在任务执行时,一个对上的guard zone可以确保任务栈不超过其预定义的大小上限,以免搞崩其他数据或任务栈;一个对下的guard zone可以确保对任务栈的访问不低于其栈底空间,以免于由缓冲区移除导致的内存崩溃。

10. 任务信息

任务信息是动态的,除非任务挂起,否则任务信息所反馈的信息可能不是最新的。可以使用如下函数获取任务信息。

VxWorks 7 Multiply Tasks

11. 任务执行控制

以下函数可用于控制任务的执行状态:

VxWorks 7 Multiply Tasks

<p如果需要将任务延迟半秒,可以使用如下方式:


taskDelay(sysClkRateGet()/2)

其中,sysClkRateGet()函数返回了每秒的系统时钟数。使用taskDelay(0),可以直接将CPU使用权让给其他任务,使自己挂起并让同优先级 的其他任务继续执行。

12. 任务调度控制

可使用如下函数实现任务调度控制。

VxWorks 7 Multiply Tasks

13. 任务删除及删除保护

任务可以被动态地删除,也可以通过保护措施避免被其他任务删除。具体函数如下:

VxWorks 7 Multiply Tasks

删除保护

任务在执行关键代码时,为了避免被删除,可以通过增加其删除保护计数器来实现任务保护。具体方法包括:

  • 调用taskSafe();
  • 获取使用了SEM_DELETE_SAFE选项的互斥信号量。

对于使用SEM_DELETE_SAFE选项的信号量,在使用semTake()获取它时,效果类似于调用taskSafe();在使用semGive()释放它时,效果类似于调用taskUnsafe()。

当任务执行完关键代码后,为了允许被其他函数删除,需要减少其删除保护计数器。具体方法包括:

  • 调用taskUnsafe();
  • 释放具有删除保护属性的互斥信号量。

14. 任务扩展:使用钩子函数

VxWorks提供钩子函数管理API,用于注册在创建、删除或任务切换时所需触发的钩子函数。具体函数接口如下:

VxWorks 7 Multiply Tasks

15. 任务错误状态:errno

C函数库中使用了一个全局整型变量errno,用于反馈函数执行错误时的具体错误码。此由ANSI C标准中所规定。

注意:当前描述的内容主要针对VxWorks,对于SMP需要另外考虑。

errno的分层定义

在VxWorks内核中,同时使用了两种方法定义errno:

  • ANSI C全局变量errno;
  • errno.h中定义的一个宏errno,该宏定义调用一个函数__errno()。该函数返回全局变量errno的地址。使用该方法的好处是:因为__errno()是一个函数,所以可以在调试时为其添加断点,从而确定是否有错误发生。

每个任务具有独立的errno值

为了在多任务环境下使用errno,VxWorks为每个任务保留了相应的errno。因此,在每次进行任务切换时,内核将errno作为任务栈的一部分保存在任务栈中。

16. 任务异常处理

信号(signal)可以用于标识软件或硬件异常。

17. 共享代码与重入

供多个任务执行的一份代码被称为共享代码,共享代码必须是可重入的。

18. 内核任务环境变量

默认情况下,内核任务共享相同的环境变量。但是如果一个任务在创建时使用了VX_PRIVATE_ENV选项,那么它就可以拥有私有的环境变量。

envLib环境变量API

envLib库提供了兼容Unix的环境变量功能。具体函数结果如下:

VxWorks 7 Multiply Tasks