0. 阐述对任务的理解,对比任务与C函数的异同点。
- 从代码上看,uCOS-II的任务就是一个函数。但是只是采用函数的形式,仅仅借用了函数的一些特性,用函数来来存储代码而已。它不是通过不同的代码来区分不同的任务,而是通过不同的任务堆栈和不同的任务优先级来进行区分。类似与C++和JAVA中的函数重载。 例如,我们可以创建10个任务的任务代码的指针都是Task,这意味着这10个任务共用一段代码,但它们有不同的任务初始化参数、不同的任务堆栈和不同的优先级。
从结构上看,uCOS-II的任务由任务程序代码(函数)、任务私有堆栈和任务控制块三部分组成。任务控制块用于关联任务代码,记录任务属性;任务私有堆栈用于保存任务的工作环境虚拟CPU寄存器;任务程序代码就是任务的执行部分了。
问:任务堆栈中有PC指向任务程序代码,为什么在任务控制块中还有指向任务的指针呢?
答:PC的值总是指向待执行指令的地址,它反映的是一个程序的运行进度(任务切换和中断时的断点都需保存真正CPU的PC到任务堆栈的PC中)。而TCB中指向任务的指针是描述任务的人口地址,在创建完首次运行任务时需要通过这个指针找到任务程序代码在内存中的位置。任务与C函数的相同点:都有返回值和形式参数
- 任务与C函数的不同点:任务绝不会被其他任务调用,即使是main函数也不能调用,在系统中各个任务与main( )处于平等地位,它们何时被运行以及何时被中止是OS调度的。也绝不会有返回值,所以返回参数定义为void。形式参数声明为void *类型,该指针用于装载传递任务的参数,可以是变量的地址、数据结构或函数的入口地址等任何需要的参数。这个参数很重要,可以利用它建立许多不同的任务,但这些不同的任务共用一段代码。
- 注意:main( )毕竟是一个应用程序的主函数,是程序运行的入口点,所以它虽然不调用任务,但是要负责任务的创建并将它们交给系统,至于何时运行它们,则与主函数无关!
1. 什么是任务控制块(TCB)?
- uCOS-II中用于记录任务信息(任务堆栈指针、任务当前状态、任务优先级别等)的数据结构。相当于任务在系统中的身份证,系统就是通过任务控制块来感知和管理任务的,没有任务控制块的任务不能被系统承认和管理。
- uCOS-II 将系统中的所有 TCB 构成两个链表(OSTCBList与OSTCBFreeList)进行任务管理。
- 空任务控制块链表 —-未被分配的 TCB 链 OSTCBFreeList。
- 任务控制块链表 —- 已分配的 TCB 链 OSTCBList。
2. 任务控制块是怎样的数据结构?
- 是一个结构体类型数据,通过typedef 把struct os_tcb { }结构体类型重命名为OS_TCB
/*
*********************************************************************************************************
TASK CONTROL BLOCK
*********************************************************************************************************
*/
typedef struct os_tcb {
/* OSTCBStkPtr指向当前任务栈顶的指针。把它放在数据结构的最前面,即偏移量为0的位置,从而使得在汇编语言中
处理这个变量较为容易,因为任务切换的核心工作是:任务堆栈指针的切换,使用更频繁。 */
OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */
struct os_tcb *OSTCBNext; /* Pointer to next TCB in the TCB list */
struct os_tcb *OSTCBPrev; /* Pointer to previous TCB in the TCB list */
INT32U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */
INT8U OSTCBStat; /* Task status */
INT8U OSTCBStatPend; /* Task PEND status */
INT8U OSTCBPrio; /* Task priority (0 == highest) */
INT8U OSTCBX; /* Bit position in group corresponding to task priority */
INT8U OSTCBY; /* Index into ready table corresponding to task priority */
OS_PRIO OSTCBBitX; /* Bit mask to access bit position in ready table */
OS_PRIO OSTCBBitY; /* Bit mask to access bit position in ready group */
} OS_TCB;
3.如何用C语言建立一个任务控制块数组?
- uCOSII在初始化时按照配置文件所设定的任务数事先定义一批空白任务块(全局变量),这样当程序创建一个任务需要一个任务控制块时,只要拿一个空白块填上任务的属性即可。
OS_TCB OSTCBTbl [ OS_MAX_TASKS + OS_N_SYS_TASKS ]; /* Table of TCBs */
OS_CFG.H 文件中的宏常数 OS_MAX_TASKS —- 用于定义最大用户任务数。
UCOS_II.H 文件中的宏常数 OS_N_SYS_TASKS —- 用于约定系统任务数,其值固定为 2 。
4. 如何加快对建立的任务控制块数组的访问?
- 任务控制块创建为双向链表。
- 创建一个结构体指针数组OSTCBPrioTbl[ ]任务优先表 :OS_TCB* 数据类型的数组,以 优先级Prio为下标存放指向各个已使能任务控制块的指针,来加速 TCB 的访问。
- 人们把正在占有CPU而处于运行状态的任务所属的控制块叫当前任务控制块。由于它是uCOS-II访问频率最高的控制块,所以专门定义了一个全局变量OS_TCB *OSTCBCur指向当前正在运行的任务的 TCB 。
5. 论述任务控制块空闲链表的初始化构建过程
- 系统在调用函数OSInit( )对uCOS-II系统进行初始化时,就先在RAM中建立一个OS_TCB结构类型的数组OSTCBTbl[ ](见上面3),然后把数组各个结构体元素链接成一个如下图的单向空任务链表,即相当于是一些空白的身份证。任务一旦建立,空任务控制块指针OSTCBFreeList指向的任务控制块便赋给了该任务,然后OSTCBFreeList指向链表中下一个空的任务控制块。一旦任务被删除,任务控制块就还给空任务链表。
void OSInit (void)
{
……
OS_InitTCBList(); /* Initialize the free list of OS_TCBs */
……
}
/*
*********************************************************************************************************
6. INITIALIZATION
7. INITIALIZE THE FREE LIST OF TASK CONTROL BLOCKS
8. - Description: This function is called by OSInit() to initialize the free list of OS_TCBs.
9. - Arguments : none
10. - Returns : none
*********************************************************************************************************
*/
static void OS_InitTCBList (void)
{
INT8U ix;
INT8U ix_next;
OS_TCB *ptcb1;
OS_TCB *ptcb2;
OS_MemClr((INT8U *)&OSTCBTbl[0], sizeof(OSTCBTbl)); /* Clear all the TCBs */
OS_MemClr((INT8U *)&OSTCBPrioTbl[0], sizeof(OSTCBPrioTbl)); /* Clear the priority table */
for (ix = 0u; ix < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1u); ix++)
{ /* Init. list of free TCBs */
ix_next = ix + 1u;
ptcb1 = &OSTCBTbl[ix];
ptcb2 = &OSTCBTbl[ix_next];
ptcb1->OSTCBNext = ptcb2;