大家好,又见面了,我是你们的朋友全栈君。
从零开始学习UCOSII操作系统4–任务管理
1、重讲任务
(1)任务可以是一个无限的循环,也可以在一次执行完毕后被删除。
这里需要注意的是,任务的代码并不是真正的删除了,而是UCOSII不再理会该任务代码,所以该任务代码不会再执行。
(2)建立任务,OSTaskCreate()
如果想让UCOSII管理用户的任务,必须先建立任务,可以通过将任务的地址(函数名)和其他参数传递到这2个函数中来建立任务。
(3)任务可以在多任务调度之前开始建立,也可以在其他的任务中创建需要的任务。但是有一点需要注意的是,在启动UCOS之前必须至少得建立一个任务。
2、分析创建任务函数
(1)参数分析:
参数1:任务的函数名:其实就是为了在任务切换的时候跳转到任务中执行的入口地址。
参数2:传递给建立任务的参数,这个参数基本不会用到。
参数3:传递给建立任务的堆栈,每个任务都有独一无二的堆栈。
参数4:传递给任务的优先级。
(2)函数内容分析:
当OS_TASK_CREATE_EN宏大于0的时候,
我们才可以使用创建任务的函数。
如果创建的时候检测到任务的优先级比最大的优先级(数值上,实际上是最小)还大的话,那么就直接退出,输出一个错误码。
我们不允许创建任务是在中断中进行的,所以我们也会在中断时创建任务返回一个错误码。
最后就是把刚刚的四个参数赋值到任务当中去,实现任务的创建。
#if OS_TASK_CREATE_EN > 0u
INT8U OSTaskCreate (void (*task)(void *p_arg),
void *p_arg,
OS_STK *ptos,
INT8U prio)
{
OS_STK *psp;
INT8U err;
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508
if (OSSafetyCriticalStartFlag == OS_TRUE) {
OS_SAFETY_CRITICAL_EXCEPTION();
}
#endif
#if OS_ARG_CHK_EN > 0u
if (prio > OS_LOWEST_PRIO) { /* 确认优先级在一个合法的范围内 */
return (OS_ERR_PRIO_INVALID);
}
#endif
OS_ENTER_CRITICAL();
if (OSIntNesting > 0u) { /* 确保我们不在中断中创建任务 */
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_CREATE_ISR);
}
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* 初始化任务的优先级 */
OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ... */
/* ... the same thing until task is created. */
OS_EXIT_CRITICAL();
psp = OSTaskStkInit(task, p_arg, ptos, 0u); /* 初始化任务堆栈 */
err = OS_TCBInit(prio, psp, (OS_STK *)0, 0u, 0u, (void *)0, 0u);
if (err == OS_ERR_NONE) {
if (OSRunning == OS_TRUE) { /* Find highest priority task if multitasking has started */
OS_Sched();
}
} else {
OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others */
OS_EXIT_CRITICAL();
}
return (err);
}
OS_EXIT_CRITICAL();
return (OS_ERR_PRIO_EXIST);
}
#endif
3、再谈任务堆栈
任务的堆栈可以使用静态的堆栈生成,也可以使用动态的堆栈生成。
(1)静态堆栈:
static OS_STK MyTaskStack[stack_size];
(2)动态堆栈:
OS_STK *pstk;
pstk = (OS_STK *)malloc(stack_size);
if(pstk != (OS_STK *)0)
{
//确保malloc能够得到足够的内存空间
}
(3)UCOSII支持的堆栈可以是递减的,也可以是递增的。
在调用函数OS_TaskCreate(),必须知道堆栈是递减的,还是递增的。
因为必须把堆栈的栈顶地址传递给上面的两个函数。
PS:这里面就有OS_CPU.h文件中的OS_STK_GROWTH为0,需要将堆栈的最低地址传递给任务创建的函数。
这个是堆栈从下往上增长的:
OS_STK TaskStack[TASK_STACK_SIZE];
OSTaskCreate(task, pdata, &TaskStack[0], prio);
这个是堆栈从上往下增长的:
OS_STK TaskStack[TASK_STACK_SIZE];
OSTaskCreate(task, pdata, &TaskStack[TASK_STACK_SIZE-1], prio);
4、删除任务,OSTaskDel()
(1)有时候我们需要删除任务,就是说任务返回到休眠状态,并不是说任务代码被删除了,而是仅仅从就绪队列中删除了而已。
参数1:prio :也就是该任务的优先级,
当我们支持多任务相同优先级的时候,必须指明任务堆栈,或者任务名,才能删除。
(2)实现这个函数的关键步骤:也就是我做中文注释的地方:
4.2.1、把任务从就绪表中移除,也就是不让该任务处于就绪状态中。
4.2.2、假如任务需要事件控制块,消息队列,邮箱等,那么我们就需要在删除任务之前将他所在的链表中移除。
4.2.3、把任务的各种资源释放掉。
#if OS_TASK_DEL_EN > 0u
INT8U OSTaskDel (INT8U prio)
{
#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
OS_FLAG_NODE *pnode;
#endif
OS_TCB *ptcb;
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
if (OSIntNesting > 0u) { /* See if trying to delete from ISR */
return (OS_ERR_TASK_DEL_ISR);
}
if (prio == OS_TASK_IDLE_PRIO) { /* Not allowed to delete idle task */
return (OS_ERR_TASK_DEL_IDLE);
}
#if OS_ARG_CHK_EN > 0u
if (prio >= OS_LOWEST_PRIO) { /* Task priority valid ? */
if (prio != OS_PRIO_SELF) {
return (OS_ERR_PRIO_INVALID);
}
}
#endif
/*$PAGE*/
OS_ENTER_CRITICAL();
if (prio == OS_PRIO_SELF) { /* See if requesting to delete self */
prio = OSTCBCur->OSTCBPrio; /* Set priority to delete to current */
}
ptcb = OSTCBPrioTbl[prio];
if (ptcb == (OS_TCB *)0) { /* Task to delete must exist */
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NOT_EXIST);
}
if (ptcb == OS_TCB_RESERVED) { /* Must not be assigned to Mutex */
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_DEL);
}
OSRdyTbl[ptcb->OSTCBY] &= (OS_PRIO)~ptcb->OSTCBBitX;
if (OSRdyTbl[ptcb->OSTCBY] == 0u) { /* 把该任务从就绪表中删除,也就是置0处理 */
OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
}
#if (OS_EVENT_EN)
if (ptcb->OSTCBEventPtr != (OS_EVENT *)0) {
OS_EventTaskRemove(ptcb, ptcb->OSTCBEventPtr); /* 把该任务从事件控制块的列表中移除 */
}
#if (OS_EVENT_MULTI_EN > 0u)
if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) { /* Remove this task from any events' wait lists*/
OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
}
#endif
#endif
#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
pnode = ptcb->OSTCBFlagNode;
if (pnode != (OS_FLAG_NODE *)0) { /* If task is waiting on event flag */
OS_FlagUnlink(pnode); /* 从事件标志组中移除 */
}
#endif
ptcb->OSTCBDly = 0u; /* 禁止时间等待 */
ptcb->OSTCBStat = OS_STAT_RDY; /* Prevent task from being resumed */
ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
if (OSLockNesting < 255u) { /* Make sure we don't context switch */
OSLockNesting++;
}
OS_EXIT_CRITICAL(); /* Enabling INT. ignores next instruc. */
OS_Dummy(); /* ... Dummy ensures that INTs will be */
OS_ENTER_CRITICAL(); /* ... disabled HERE! */
if (OSLockNesting > 0u) { /* Remove context switch lock */
OSLockNesting--;
}
OSTaskDelHook(ptcb); /* Call user defined hook */
OSTaskCtr--; /* One less task being managed */
OSTCBPrioTbl[prio] = (OS_TCB *)0; /* Clear old priority entry */
if (ptcb->OSTCBPrev == (OS_TCB *)0) { /* Remove from TCB chain */
ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0;
OSTCBList = ptcb->OSTCBNext;
} else {
ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext;
ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev;
}
ptcb->OSTCBNext = OSTCBFreeList; /* Return TCB to free TCB list */
OSTCBFreeList = ptcb;
#if OS_TASK_NAME_EN > 0u
ptcb->OSTCBTaskName = (INT8U *)(void *)"?";
#endif
OS_EXIT_CRITICAL();
if (OSRunning == OS_TRUE) {
OS_Sched(); /* Find new highest priority task */
}
return (OS_ERR_NONE);
}
#endif
5、挂起任务,OS_TaskSuspend()和恢复挂起任务OSTaskResume()
(1)这个函数是必须进行说明的一个函数,因为他涉及到任务的状态机。
(2)这个实现挂起的函数主要是删除就绪表中的位图的相应优先级的那个位进行置0的操作。
(3)然后将任务的相应的状态进行赋值为挂起的状态。
(4)最后在最后要进行任务的调度的操作,如果当前是这个任务在进行的话,要切换到别的任务中继续去运行。
INT8U OSTaskSuspend (INT8U prio)
{
BOOLEAN self;
OS_TCB *ptcb;
if (prio == OS_IDLE_PRIO) { (1)
return (OS_TASK_SUSPEND_IDLE);
}
if (prio >= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { (2)
return (OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
if (prio == OS_PRIO_SELF) { (3)
prio = OSTCBCur->OSTCBPrio;
self = TRUE;
} else if (prio == OSTCBCur->OSTCBPrio) { (4)
self = TRUE;
} else {
self = FALSE;
}
if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { (5)
OS_EXIT_CRITICAL();
return (OS_TASK_SUSPEND_PRIO);
} else {
if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) { (6)//就绪表中的相应的位置0操作
OSRdyGrp &= ~ptcb->OSTCBBitY;
}
ptcb->OSTCBStat |= OS_STAT_SUSPEND; (7) 把TCB的状态也设置为挂起的状态标志位
OS_EXIT_CRITICAL();
if (self == TRUE) { (8)
OSSched();
}
return (OS_NO_ERR);
}
}
OSTaskResume()恢复任务的源码也是差不多的,就是一个是对就绪表上面的内容进行置0的操作,一个是对就绪表的内容进行置1的操作。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/141855.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...