从零开始学习UCOSII操作系统4–任务管理

从零开始学习UCOSII操作系统4–任务管理从零开始学习UCOSII操作系统4–任务管理1、重讲任务(1)任务可以是一个无限的循环,也可以在一次执行完毕后被删除。这里需要注意的是,任务的代码并不是真正的删除了,而是UCOSII不再理会该任务代码,所以该任务代码不会再执行。(2)建立任务,OSTaskCreate()如果想让UCOSII管理用户的任务,必须先建立任务,可以通过将任务的地址(函数名)和其他参数传递到

大家好,又见面了,我是你们的朋友全栈君。

从零开始学习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的操作。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/141855.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • javascript百炼成仙 第一章 掌握JavaScript基础 1.2直接量

    javascript百炼成仙 第一章 掌握JavaScript基础 1.2直接量叶小凡的住处被安排在青山院西北角的一个房间里,虽不宽敞,倒也干净。叶小凡两眼露出振奋的眼神,随便吃了点乡亲们准备的干粮后,就立刻开始打坐修行。编程之修,重在积累,而非资质。资质虽然一样重要,可是后天的努力一样必不可少。这些道理,叶小凡还未上山之前,就已经熟知!因此,即便是资质平凡,只要肯下苦功,一样可以修得正果!叶小凡虽然甲等资质,可依然不骄不躁,开始从“JavaScript基础修炼要诀”第一页开始看起。修炼要诀第一章,直接量。编程世界,所谓直接量,就是明面上可以见到的数据值。常见的直接量有数字,小数,

    2022年6月11日
    42
  • 静态方法中可以访问非静态成员变量_多线程局部变量会不会互相影响

    静态方法中可以访问非静态成员变量_多线程局部变量会不会互相影响静态内部类访问包含它的外部类的非静态成员变量时,可以通过new外部类().成员的方式访问,这是因为静态的只能访问静态的,因为他们在对象没创建前就存在了。如果想访问非静态的则必须初始化该对象,因为只有初始化后对象在内存才存在(静态的除外)…

    2022年8月31日
    4
  • 校验和计算原理_CRC校验原理及代码

    校验和计算原理_CRC校验原理及代码校验和思路首先,IP、ICMP、UDP和TCP报文头都有检验和字段,大小都是16bit,算法基本上也是一样的。在发送数据时,为了计算数据包的检验和。应该按如下步骤:1、把校验和字段设置为0;2、把需要校验的数据看成以16位为单位的数字组成,依次进行二进制反码求和;3、把得到的结果存入校验和字段中在接收数据时,计算数据包的检验和相对简单,按如下步骤:1、把首部看成以16位为单位的数字组成,依次进行二

    2025年7月16日
    0
  • 如何使用Fiddler模拟弱网情况对app进行测试「建议收藏」

    前言很多时候,我们需要在弱网情况下,对app进行测试,不可能将app放置到离路由器很远的地方,这里可以模拟弱网来测试app。那么,我们这里使用Fiddler工具来模拟弱网。使用speedtest在线测速工具来测试网络。一、Fiddler工具连接手机,设置代理打开Fiddler,进入到Tools—>options,如图所示:再次选择Connection

    2022年4月10日
    60
  • centos搭建YApi接口管理平台

    centos搭建YApi接口管理平台

    2021年6月4日
    126
  • 内部服务器500错误原因解决方法_什么是内部服务器错误

    内部服务器500错误原因解决方法_什么是内部服务器错误http500内部服务器错误的解决方法这个错误整整浪费了我下午的时间,在网上有很多的方法,当然我也是从那些繁多的方法中一点点的搞定IIS的,首先你要先装好IIS,XPSP2中的应该是5.1版本的,安装方法:1->打开控制面板,选择添加删除程序2->选择添加删除组件,选择Internet信息服务,也就是IIS3->点击下一步安装就好了安装好之后也许你的机子会正常的显示http://localho

    2022年8月11日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号