VxWorks 学习(二)任务Task
该系列文章是我根据多个博主以及相关书上内容整理的学习笔记,许多内容非原创。
VxWorks中的任务
相关概念
由于之前在研究生过程中接触的都是C++和相应的应用开发,使用的操作系统都是Linux,因此在我观念中只有进程、线程以及协程的相关知识。
- 进程:进程是一个动态的概念,它是程序的一次执行过程,包括了动态创建、调度、执行和消亡的整个过程(这一系列都由操作系统的调度机制来完成!) 它是程序执行和资源管理的最小单位。进程不但包括程序的指令和数据,而且包括程序计数器和处理器的所有寄存器以及存储临时数据的进程堆栈。从操作系统的角度看,进程是程序执行时相关资源的总称。当进程结束时,所有资源被操作系统自动回收。
- 线程:前面已经提到,进程是系统中程序执行和资源分配的基本单位。每个进程都拥有自己的数据段、代码段和堆栈段,这就造成了进程在进行切换时操作系统的开销比较大。为了提高效率,操作系统又引入了另一个概念——线程,也称为轻量级进程。线程是进程上下文中执行的代码序列,又称为轻量级的进程。它是操作系统能够调度的最小单元。线程可以对进程的内存空间和资源进行访问,并与同一进程中的其他线程共享。因此,线程的上下文切换的开销比进程小得多。一个进程可以拥有多个线程,其中每个线程共享该进程所拥有的资源。要注意的是,由于线程共享了进程的资源和地址空间,因此,任何线程对系统资源的操作都会给其他线程带来影响。由此可知,多线程中的同步是非常重要的问题。
进程的上下文以及多线程间同步异步知识在我身上已经成为一种思维定式,现在开始工作,需要我开始学习VxWorks以及相关的知识,有很多东西真的由于操作系统的不同而有着明显的差异化。
例如VxWorks中没有进程和线程的概念,转而是任务Task,对于实时操作系统来说,任务也称作一个线程,是一个简单的程序。每个任务被赋予一定的优先级,有它自己的一套CPU寄存器和自己的栈空间。
Vxworks 是实时操作系统,这决定了他的任务调度必须是基于优先级的,而且必须是可抢占式调度方式,这样才能够区分实际情况下不同状态的处理级别,对高优先级的情况进行优先响应。
任务状态
这一块与进程间的状态有很多相同的地方。
VxWorks中,任务有五种状态:就绪态、休眠态、延迟态、悬置态、运行态。就绪态同样是具备了除CPU时间片以外的所有资源,当其他任务释放CPU便可以运行;休眠态和阻塞态相同,需要除CPU以外的其他资源;延迟态是指任务主动放弃CPU,延迟执行一段时间,不需要其他以外的资源;悬置态是一种用于调试的状态,处于该状态的任务不会因为其不运行而导致状态的转换(这句暂时还没理解);单核心系统下,处于运行态的任务只有一个,这样的任务不需要其他资源,也不需要等待时间延迟,通常是由最高优先级的就绪态任务转换而来的,若就绪队列为空,系统将会运行一个IDLE任务。具体其他任务状态如下表所示。
不同任务间的切换如下图所示。
VxWorks为任务状态之间的转换所提供的API如下所示:
任务创建以及优先级调度
所需头文件 <taskLib.h>
1. 任务创建函数
id = taskSpawn(name, priority, options, stacksize, main, arg1, arg10);
taskInit();
taskActive();
//id 为4个字节 int
//name: 任务名
//stacksize:任务堆栈
//options:任务选项
//main:入口函数地址
//arg10:传给入口函数的启动参数
//示例:
tid = taskSpawn("tMyTask", 90, VX_FP_TASK, 20000, myFunc, 2387, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2. 任务删除
exit();//终止任务调用,释放内存
taskDelete();//终止指定任务,释放内存
taskSafe();//保护调用任务免于删除
taskUnsafe();//解除任务删除保护
注意删除任务之前,应先释放该任务所占有的共享资源。也需要注意,若某个任务需要访问临界区,若该任务释放时,同时对其持有的信号量进行删除,这将导致其他任务无法对该临界区进行访问。此时应调用taskSafe()保护该任务被删除。
3. 创建一个任务并运行在指定的CPU核上
.h文件
#include <cpuset.h>
#include <taskLib.h>
.c文件
STATUS affinitySetExample(void)
{
cpuset_t affinity;
int tid;
/* Create the task but only activate it after setting its affinity */
tid = taskCreate ("myCpu1Task", 100, 0, 5000, printf, (int) "myCpu1Task executed on CPU 1 !", 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (tid == NULL)
return (ERROR);
/* Clear the affinity CPU set and set index for CPU 1 */
CPUSET_ZERO (affinity);
CPUSET_SET (affinity, 1);
if (taskCpuAffinitySet (tid, affinity) == ERROR)
{
/* Either CPUs are not enabled or we are in UP mode */
taskDelete (tid);
return (ERROR);
}
/* Now let the task run on CPU 1 */
taskActivate (tid);
return (OK);
}
任务优先级
Wind内核有256个优先级,编号是0-255,0的优先级最高,255最低。在VxWorks 系统中,所有应用程序任务的优先级应该在 100~ 250 之间;至于驱动程序创建的任务的优先级可以位于 51~99 之间, 系统网络任务 tNetTask 的优先级默认值为 50。
代码示例
.h 文件
#include "vxWorks.h"
#include "taskLib.h"
#include "kernelLib.h"
#include "sysLib.h"
#define ITER1 100
#define ITER2 10
#define HIGH 100 /* high priority */
#define MID 101 /* medium priority */
#define LOW 102 /* low priority */
#define LONG_TIME 0xFFFFFFL
.c 文件
void sched(void) /* function to create the two tasks */
{
int taskIdOne, taskIdTwo, taskIdThree, taskIdFour;
printf("\n\n\n\n\n");
/* spawn the three tasks */
if ((taskIdOne = taskSpawn("task1", LOW, 0x100, 20000, (FUNCPTR)taskOne, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
printf("taskSpawn taskOne failed\n");
if ((taskIdTwo = taskSpawn("task2", MID, 0x100, 20000, (FUNCPTR)taskTwo, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
printf("taskSpawn taskTwo failed\n");
if ((taskIdThree = taskSpawn("task3", HIGH, 0x100, 20000, (FUNCPTR)taskThree,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
printf("taskSpawn taskThree failed\n");
if ((taskIdFour = taskSpawn("task4", HIGH, 0x100, 20000, (FUNCPTR)taskFour,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
printf("taskSpawn taskFour failed\n");
}
void taskOne(void)
{
unsigned int i, j;
for (i = 0; i < ITER1; i++)
{
/* log messages */
for (j = 0; j < ITER2; j++)
printf("task1\n");
/* allow time for context switch */
for (j = 0; j < LONG_TIME; j++)
;
}
}
void taskTwo(void)
{
unsigned int i, j;
for (i = 0; i < ITER1; i++)
{
/* log messages */
for (j = 0; j < ITER2; j++)
printf("task2\n");
/* allow time for context switch */
for (j = 0; j < LONG_TIME; j++)
;
}
}
void taskThree(void)
{
unsigned int i, j;
for (i = 0; i < ITER1; i++)
{
/* log messages */
for (j = 0; j < ITER2; j++)
printf("task3\n");
/* allow time for context switch */
for (j = 0; j < LONG_TIME; j++)
;
}
}
void taskFour(void)
{
taskDelay(TIMESLICE / 10);
taskPrioritySet(taskIdOne, HIGH - 1);
}
task4延迟100毫秒后,将task1的优先级设置到最高:在task2任务运行输出“task2”的过程中,task1抢占了task2的CPU资源,先是输出了所有的“task1”,最后剩余的“task2”得以输出。
在VxWorks中,我们可以使用taskPrioritySet()函数来动态改变任务的优先级,这个函数的原型是:
STATUS taskPrioritySet (int tid, /* task ID */ int newPriority /* new priority */ );