μC/OS-Ⅱ源码学习(6)---事件标志组

快速回顾

μC/OS-Ⅱ中的多任务

μC/OS-Ⅱ源码学习(1)---多任务系统的实现

μC/OS-Ⅱ源码学习(2)---多任务系统的实现(下)

μC/OS-Ⅱ源码学习(3)---事件模型

μC/OS-Ⅱ源码学习(4)---信号量

μC/OS-Ⅱ源码学习(5)---消息队列

        本文进一步解析事件模型中,事件标志组类型的函数源码。

简单介绍

        事件标志组(Event flag group)是一种特殊的事件,其事件控制块为:

//ucos_ii.h
typedef struct os_flag_grp {INT8U         OSFlagType;         /* 事件标志组类型 */void         *OSFlagWaitList;     /* 等待链表,里面的每一个节点都记录了相关任务等待事件标志位的信息 */OS_FLAGS      OSFlagFlags;        /* 当前存在的标志 */
#if OS_FLAG_NAME_EN > 0uINT8U        *OSFlagName;
#endif
} OS_FLAG_GRP;

        与其他事件不同,事件标志组不共享OS_EVENT结构,而是有自己特殊的结构OS_FLAG_GRP。其中OS_FLAGS的长度是可以设定的,表示一个事件标志组内最多有多少种标志:

//ucos_ii.h
#if OS_FLAGS_NBITS == 8u
typedef  INT8U    OS_FLAGS;
#endif#if OS_FLAGS_NBITS == 16u
typedef  INT16U   OS_FLAGS;
#endif#if OS_FLAGS_NBITS == 32u
typedef  INT32U   OS_FLAGS;
#endif

        OSFlagWaitList链表用来记录等待该事件标志组的所有任务及其需求,通常通常用一个节点对象OS_FLAG_NODE来保存这些信息:

//ucos_ii.h
typedef struct os_flag_node {void         *OSFlagNodeNext;          /* 等待列表的下一个节点 */void         *OSFlagNodePrev;          /* 等待列表的前一个节点 */void         *OSFlagNodeTCB;           /* 指向等待该事件标志组的任务,和下一个成员相匹配 */void         *OSFlagNodeFlagGrp;       /* 指向等待的事件标志组          */OS_FLAGS      OSFlagNodeFlags;         /* 等待的标志位 */INT8U         OSFlagNodeWaitType;      /* 等待类型,即任意匹配或全部匹配等 */
} OS_FLAG_NODE;

       回忆其它事件(如信号量、消息队列,以下简称普通事件)的等待表,都是使用类似就绪表的方式来快速检索。这是因为普通事件类型在pend时,无需记录其它的等待信息,例如一个任务通过pend函数等待一个普通事件时,该普通事件只需要记录该任务的优先级,当普通事件发生后,直接查表来通知对应的任务即可。

        而事件标志组在pend过程中需要记录的信息就多了一些,比如不同任务执行所需要的标志位可能是不一样的,这就导致简单使用等待表的方式会丢失这些信息。μC/OSⅡ将这些信息记录在一个个节点中,并用遍历链表的方式查找满足条件的任务。

        可以说,不同的等待结构和方式,是事件标志组区分于其它事件的根本原因,也因此,μC/OSⅡ使用了额外的控制块类型OS_FLAG_GRP来实现事件标志组。

事件标志组的创建

        对应函数为OSFlagCreate(OS_FLAGS flagsINT8U *perr),需要传入一个标志作为初始值,返回一个初始化后的事件标志组控制块。

//os_flag.c
OS_FLAG_GRP  *OSFlagCreate (OS_FLAGS  flags,INT8U    *perr)
{OS_FLAG_GRP *pgrp;
#if OS_CRITICAL_METHOD == 3u        /* 初始化临界区变量 */OS_CPU_SR    cpu_sr = 0u;
#endif#ifdef OS_SAFETY_CRITICALif (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();}
#endif#ifdef OS_SAFETY_CRITICAL_IEC61508if (OSSafetyCriticalStartFlag == OS_TRUE) {OS_SAFETY_CRITICAL_EXCEPTION();}
#endifif (OSIntNesting > 0u) {         /* 不能在中断中调用 */*perr = OS_ERR_CREATE_ISR;   return ((OS_FLAG_GRP *)0);}OS_ENTER_CRITICAL();pgrp = OSFlagFreeList;        /* 获取一个新的事件标志组控制块 */if (pgrp != (OS_FLAG_GRP *)0) {       /* 查看是否是有效控制块 *//* 如果是一个有效控制块,则将原链表头指向下一个,完成首个控制块的脱离 */OSFlagFreeList       = (OS_FLAG_GRP *)OSFlagFreeList->OSFlagWaitList;pgrp->OSFlagType     = OS_EVENT_TYPE_FLAG;  /* 设置为事件标志组类型 */pgrp->OSFlagFlags    = flags;               /* 设置初始值 */pgrp->OSFlagWaitList = (void *)0;           /* 等待表初始化为0 */
#if OS_FLAG_NAME_EN > 0upgrp->OSFlagName     = (INT8U *)(void *)"?";
#endifOS_EXIT_CRITICAL();*perr                = OS_ERR_NONE;} else {     //没有有效的任务控制块了OS_EXIT_CRITICAL();*perr                = OS_ERR_FLAG_GRP_DEPLETED;}return (pgrp);                                  /* 返回创建的事件标志组控制块 */
}

事件标志组的操作

OS_FLAGS OSFlagPend(OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_typeINT32U timeout, INT8U *perr)

        功能描述:等待事件flags的到来,如果已经存在这些事件标志,则直接继续执行,否则阻塞等待。该函数有很多可选功能:

wait_type可以是以下值及其组合:

//os_flag.c
#define  OS_FLAG_WAIT_CLR_ALL           0u  /* 等待所有传入的事件标志的清除(0有效) */
#define  OS_FLAG_WAIT_CLR_AND           0u#define  OS_FLAG_WAIT_CLR_ANY           1u  /* 等待任意传入的事件标志的清除(0有效) */
#define  OS_FLAG_WAIT_CLR_OR            1u#define  OS_FLAG_WAIT_SET_ALL           2u  /* 等待所有传入的事件标志的出现(1有效) */
#define  OS_FLAG_WAIT_SET_AND           2u#define  OS_FLAG_WAIT_SET_ANY           3u  /* 等待任意传入的事件标志的出现(1有效) */
#define  OS_FLAG_WAIT_SET_OR            3u#define  OS_FLAG_CONSUME             0x80u  /* 当pend得到满足后,这些标志会消耗掉 */

timeout等待超时时长,当大于0时,表示等待timeout时长后系统会将该任务就绪。传入等于0时,表示一直等待直到事件标志的出现。

        接着看源码:

//os_flag.c
OS_FLAGS  OSFlagPend (OS_FLAG_GRP  *pgrp,OS_FLAGS      flags,INT8U         wait_type,INT32U        timeout,INT8U        *perr)
{OS_FLAG_NODE  node;OS_FLAGS      flags_rdy;INT8U         result;INT8U         pend_stat;BOOLEAN       consume;
#if OS_CRITICAL_METHOD == 3u       /* 初始化临界区变量 */OS_CPU_SR     cpu_sr = 0u;
#endif#ifdef OS_SAFETY_CRITICALif (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();}
#endif#if OS_ARG_CHK_EN > 0uif (pgrp == (OS_FLAG_GRP *)0) {       /* 事件标志组不能为空 */*perr = OS_ERR_FLAG_INVALID_PGRP;return ((OS_FLAGS)0);}
#endifif (OSIntNesting > 0u) {        /* 不能在中断中调用 */*perr = OS_ERR_PEND_ISR;return ((OS_FLAGS)0);}if (OSLockNesting > 0u) {        /* 调度器上锁时无法调用 */*perr = OS_ERR_PEND_LOCKED;return ((OS_FLAGS)0);}if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) {       /* 必须是事件标志组类型 */*perr = OS_ERR_EVENT_TYPE;return ((OS_FLAGS)0);}result = (INT8U)(wait_type & OS_FLAG_CONSUME);if (result != (INT8U)0) {                 /* 是否需要消耗掉这些flags */wait_type &= (INT8U)~(INT8U)OS_FLAG_CONSUME;   //清除消耗(consume)标志consume    = OS_TRUE;     //消耗标志为真} else {consume    = OS_FALSE;}
/*$PAGE*/OS_ENTER_CRITICAL();switch (wait_type) {case OS_FLAG_WAIT_SET_ALL:       /* 需要所有指定标志都出现 */flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & flags);    /* 通过按位与获取我们想要的位 */if (flags_rdy == flags) {         /* 这些位必须值为1(与所需标志相同) */if (consume == OS_TRUE) {pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy;   /* 如果需要消耗掉这些位,通过按位与取反对应位即可 */}OSTCBCur->OSTCBFlagsRdy = flags_rdy;     /* 将准备好的标志位传递给任务TCB */OS_EXIT_CRITICAL();*perr                   = OS_ERR_NONE;return (flags_rdy);} else {         /* 若标志位不满足条件,则创建节点并进行任务和标志组的双向绑定 */OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);OS_EXIT_CRITICAL();}break;case OS_FLAG_WAIT_SET_ANY:     //任意指定的标志位出现flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & flags);    /* 通过按位与互殴去我们想要的位 */if (flags_rdy != (OS_FLAGS)0) {      /* 只要有任意位满足,整个flags就不为0 */if (consume == OS_TRUE) {      /* 是否需要消耗掉这些标志 */pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy;    /* 按位与取反对应位进行清除 */}OSTCBCur->OSTCBFlagsRdy = flags_rdy;     /* 将已有的标志位传递给任务TCB */OS_EXIT_CRITICAL();*perr                   = OS_ERR_NONE;return (flags_rdy);} else {       /* 若标志位不满足条件,则创建节点并进行任务和标志组的双向绑定 */OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);OS_EXIT_CRITICAL();}break;#if OS_FLAG_WAIT_CLR_EN > 0u        /* 0有效,和上面代码逻辑是一样的 */case OS_FLAG_WAIT_CLR_ALL:flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & flags;    /* Extract only the bits we want     */if (flags_rdy == flags) {                     /* Must match ALL the bits that we want     */if (consume == OS_TRUE) {                 /* See if we need to consume the flags      */pgrp->OSFlagFlags |= flags_rdy;       /* Set ONLY the flags that we wanted        */}OSTCBCur->OSTCBFlagsRdy = flags_rdy;      /* Save flags that were ready               */OS_EXIT_CRITICAL();                       /* Yes, condition met, return to caller     */*perr                   = OS_ERR_NONE;return (flags_rdy);} else {                                      /* Block task until events occur or timeout */OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);OS_EXIT_CRITICAL();}break;case OS_FLAG_WAIT_CLR_ANY:flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & flags;   /* Extract only the bits we want      */if (flags_rdy != (OS_FLAGS)0) {               /* See if any flag cleared                  */if (consume == OS_TRUE) {                 /* See if we need to consume the flags      */pgrp->OSFlagFlags |= flags_rdy;       /* Set ONLY the flags that we got           */}OSTCBCur->OSTCBFlagsRdy = flags_rdy;      /* Save flags that were ready               */OS_EXIT_CRITICAL();                       /* Yes, condition met, return to caller     */*perr                   = OS_ERR_NONE;return (flags_rdy);} else {                                      /* Block task until events occur or timeout */OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);OS_EXIT_CRITICAL();}break;
#endifdefault:     //其他情况是非法的,返回空标志(0)OS_EXIT_CRITICAL();flags_rdy = (OS_FLAGS)0;*perr      = OS_ERR_FLAG_WAIT_TYPE;return (flags_rdy);}
/*$PAGE*/OS_Sched();        /* 尝试切换上下文 */OS_ENTER_CRITICAL();     //再次回到这里时,表明任务由于以下原因重新就绪了if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) {      /* 非标志位满足条件导致就绪 */pend_stat                = OSTCBCur->OSTCBStatPend;OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;    //pend恢复OK状态OS_FlagUnlink(&node);      //将上面绑定的节点进行解绑OSTCBCur->OSTCBStat      = OS_STAT_RDY;      /* 使任务状态变为就绪态 */OS_EXIT_CRITICAL();flags_rdy                = (OS_FLAGS)0;     //这种情况下,标志位没有意义,直接清空switch (pend_stat) {case OS_STAT_PEND_ABORT:*perr = OS_ERR_PEND_ABORT;     /* 因使用Abort函数导致的pend结束 */break;case OS_STAT_PEND_TO:default:*perr = OS_ERR_TIMEOUT;      /* 超时导致的pend结束 */break;}return (flags_rdy);}flags_rdy = OSTCBCur->OSTCBFlagsRdy;     //将外部传入的标志位赋值flags_rdy,做其它处理if (consume == OS_TRUE) {         /* 消耗标志位 */switch (wait_type) {case OS_FLAG_WAIT_SET_ALL:case OS_FLAG_WAIT_SET_ANY: pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy;     /* 将事件标志组对应位清除 */break;#if OS_FLAG_WAIT_CLR_EN > 0ucase OS_FLAG_WAIT_CLR_ALL:case OS_FLAG_WAIT_CLR_ANY:      pgrp->OSFlagFlags |=  flags_rdy;   /* 0有效,将事件标志组对应位置位 */break;
#endifdefault:    //其他情况为非法,返回空标志OS_EXIT_CRITICAL();*perr = OS_ERR_FLAG_WAIT_TYPE;return ((OS_FLAGS)0);}}OS_EXIT_CRITICAL();*perr = OS_ERR_NONE;     /* 没有错误发生,表明一定有标志位出现 */return (flags_rdy);     //返回获得的标志位
}

        具体看看事件标志组与任务的双向绑定函数OS_FlagBlock()

//os_flag.c
static  void  OS_FlagBlock (OS_FLAG_GRP  *pgrp,OS_FLAG_NODE *pnode,OS_FLAGS      flags,INT8U         wait_type,INT32U        timeout)
{OS_FLAG_NODE  *pnode_next;INT8U          y;OSTCBCur->OSTCBStat      |= OS_STAT_FLAG;      //任务状态:等待标志位OSTCBCur->OSTCBStatPend   = OS_STAT_PEND_OK;OSTCBCur->OSTCBDly        = timeout;       /* 填装等待超时 */
#if OS_TASK_DEL_EN > 0uOSTCBCur->OSTCBFlagNode   = pnode;       /* 任务等待标志位指针指向该事件标志组结点结构 */
#endif/* 标志组节点(pnode)是一个全新的空白节点,开始填装,并将其加到OSFlagWaitList链表首,原来的链表接在新节点后 */pnode->OSFlagNodeFlags    = flags;        /* 保存我们需要等待的标志位 */pnode->OSFlagNodeWaitType = wait_type;       /* 保存等待类型 */pnode->OSFlagNodeTCB      = (void *)OSTCBCur;     /* 保存当前任务的TCB */pnode->OSFlagNodeNext     = pgrp->OSFlagWaitList; /* 将新节点下一个指向原链表首 */pnode->OSFlagNodePrev     = (void *)0;pnode->OSFlagNodeFlagGrp  = (void *)pgrp;         /* 保存事件标志组 */pnode_next                = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;if (pnode_next != (void *)0) {        //首次插入链表时,链表是空的pnode_next->OSFlagNodePrev = pnode;       /* 非首次插入时,将原链表头上一个指向新创建的节点 */}pgrp->OSFlagWaitList = (void *)pnode;       /* 将链表头指向新节点 */y            =  OSTCBCur->OSTCBY;      /* 从优先级就绪表中将等待标志位的任务清除 */OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;if (OSRdyTbl[y] == 0x00u) {OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;}
}

        可以用下图表示该函数做了什么:

①事件标志组(OS_FLAG_GRP)第一次被等待时,创建首个节点(OS_FLAG_NODE),并双向引用。

②该事件标志组(OS_FLAG_GRP)第二次被等待时,将新节点填好后挂载在原链表头,原来的链表元素接续在新节点后,同时双向引用不能少。

        再看解除绑定函数OS_FlagUnlink(),就是将上面的操作反过来,解除这些链接。

//os_flag.c
void  OS_FlagUnlink (OS_FLAG_NODE *pnode)
{
#if OS_TASK_DEL_EN > 0uOS_TCB       *ptcb;
#endifOS_FLAG_GRP  *pgrp;OS_FLAG_NODE *pnode_prev;OS_FLAG_NODE *pnode_next;pnode_prev = (OS_FLAG_NODE *)pnode->OSFlagNodePrev;pnode_next = (OS_FLAG_NODE *)pnode->OSFlagNodeNext;if (pnode_prev == (OS_FLAG_NODE *)0) {         /* 前一个节点为0,表明pnode为链表首 */pgrp                 = (OS_FLAG_GRP *)pnode->OSFlagNodeFlagGrp;pgrp->OSFlagWaitList = (void *)pnode_next;        /* 将该节点脱离链表 */if (pnode_next != (OS_FLAG_NODE *)0) {pnode_next->OSFlagNodePrev = (OS_FLAG_NODE *)0;     /* 下一个节点的上一个指向0 */}} else {     //前一个节点非0pnode_prev->OSFlagNodeNext = pnode_next;     /* 上一节点的下一个,指向下一个节点 */if (pnode_next != (OS_FLAG_NODE *)0) {       /* 下一节点非空 */pnode_next->OSFlagNodePrev = pnode_prev;     /* 下一节点的上一个,指向上一个节点,完成pnode的脱离 */}}
#if OS_TASK_DEL_EN > 0uptcb                = (OS_TCB *)pnode->OSFlagNodeTCB;ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0;
#endif
}

OS_FLAGS OSFlagPost(OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U opt, INT8U *perr)

        功能描述:为事件标志组设置(或清除)一些标志位。支持一些选项opt:

//ucos_ii.h
#define  OS_FLAG_CLR     0u   //清除这些标志位
#define  OS_FLAG_SET     1u   //置位这些标志位

        接下来看源码:

//os_flag.c
OS_FLAGS  OSFlagPost (OS_FLAG_GRP  *pgrp,OS_FLAGS      flags,INT8U         opt,INT8U        *perr)
{OS_FLAG_NODE *pnode;BOOLEAN       sched;OS_FLAGS      flags_cur;OS_FLAGS      flags_rdy;BOOLEAN       rdy;
#if OS_CRITICAL_METHOD == 3u      /* 初始化临界区变量 */OS_CPU_SR     cpu_sr = 0u;
#endif#ifdef OS_SAFETY_CRITICALif (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();}
#endif#if OS_ARG_CHK_EN > 0uif (pgrp == (OS_FLAG_GRP *)0) {      /* 事件标志组不能为空 */*perr = OS_ERR_FLAG_INVALID_PGRP;return ((OS_FLAGS)0);}
#endifif (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) {     /* 事件类型必须为“事件标志组” */*perr = OS_ERR_EVENT_TYPE;return ((OS_FLAGS)0);}OS_ENTER_CRITICAL();switch (opt) {case OS_FLAG_CLR:pgrp->OSFlagFlags &= (OS_FLAGS)~flags;     /* 清除对应的标志位 */break;case OS_FLAG_SET:pgrp->OSFlagFlags |=  flags;     /* 置位对应标志位 */break;default:OS_EXIT_CRITICAL();         /* 非法选项,标记错误,返回空标志 */*perr = OS_ERR_FLAG_INVALID_OPT;return ((OS_FLAGS)0);}sched = OS_FALSE;        /* 初始化切换上下文标志,默认不切换 */pnode = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;      //获取事件标志组的等待链表while (pnode != (OS_FLAG_NODE *)0) {       /* 遍历所有的等待节点 */switch (pnode->OSFlagNodeWaitType) {      //判断等待类型case OS_FLAG_WAIT_SET_ALL:       /* 所有标志位满足 */flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & pnode->OSFlagNodeFlags);   //将任务等待的标志位和当前已有的标志位进行按位与操作if (flags_rdy == pnode->OSFlagNodeFlags) {rdy = OS_FlagTaskRdy(pnode, flags_rdy);   /* 如果已有标志位能满足任务等待的需求,则尝试就绪该任务 */if (rdy == OS_TRUE) {   //是否成功就绪(在优先级就绪表置位)sched = OS_TRUE;       /* 将切换标志置位 */}}break;case OS_FLAG_WAIT_SET_ANY:      /* 任意标志位满足 */flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & pnode->OSFlagNodeFlags);if (flags_rdy != (OS_FLAGS)0) {     //只有不为0,说明存在标志位满足条件rdy = OS_FlagTaskRdy(pnode, flags_rdy);   /* 尝试就绪等待链表中的任务 */if (rdy == OS_TRUE) {sched = OS_TRUE;}}break;#if OS_FLAG_WAIT_CLR_EN > 0u     /* 0有效,其它和上面代码逻辑相同 */case OS_FLAG_WAIT_CLR_ALL:flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags;if (flags_rdy == pnode->OSFlagNodeFlags) {rdy = OS_FlagTaskRdy(pnode, flags_rdy);if (rdy == OS_TRUE) {sched = OS_TRUE;}}break;case OS_FLAG_WAIT_CLR_ANY:flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags;if (flags_rdy != (OS_FLAGS)0) {rdy = OS_FlagTaskRdy(pnode, flags_rdy);if (rdy == OS_TRUE) {sched = OS_TRUE;}}break;
#endifdefault:     //非法选项,标记错误,并返回空标志OS_EXIT_CRITICAL();*perr = OS_ERR_FLAG_WAIT_TYPE;return ((OS_FLAGS)0);}pnode = (OS_FLAG_NODE *)pnode->OSFlagNodeNext;    /* 节点指向链表中的下一个 */}OS_EXIT_CRITICAL();if (sched == OS_TRUE) {    //若切换标志位为真,则尝试上下文切换OS_Sched();}OS_ENTER_CRITICAL();flags_cur = pgrp->OSFlagFlags;OS_EXIT_CRITICAL();*perr     = OS_ERR_NONE;return (flags_cur);    //返回事件标志组当前的标志
}

        其中函数OS_FlagTaskRdy(pnode, flags_rdy)用于就绪节点指向的任务,并将该节点从事件标志组控制块的等待链表中脱离:

//os_flag.c
static  BOOLEAN  OS_FlagTaskRdy (OS_FLAG_NODE *pnode,OS_FLAGS      flags_rdy)
{OS_TCB   *ptcb;BOOLEAN   sched;ptcb                 = (OS_TCB *)pnode->OSFlagNodeTCB;    /* 取出等待事件的任务TCB */ptcb->OSTCBDly       = 0u;     //等待超时计数器设置为0(不计数)ptcb->OSTCBFlagsRdy  = flags_rdy;    //将准备好的标志位填装到TCB中ptcb->OSTCBStat     &= (INT8U)~(INT8U)OS_STAT_FLAG;    //清除等待标志位状态ptcb->OSTCBStatPend  = OS_STAT_PEND_OK;     //pend状态设置为OKif (ptcb->OSTCBStat == OS_STAT_RDY) {       /* 任务是否就绪 */OSRdyGrp               |= ptcb->OSTCBBitY;       /* 将优先级就绪表中对应优先级置位 */OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;sched                   = OS_TRUE;} else {sched                   = OS_FALSE;}OS_FlagUnlink(pnode);     //释放该节点,从标志组的等待链表中脱离return (sched);    //返回是否需要切换任务
} 

事件标志组的删除

        函数原型:OS_FLAG_GRP OSFlagDel(OS_FLAG_GRP *pgrp, INT8U opt, INT8U *perr)

        和其它事件的删除函数一样,作用是清空控制块,并就绪正在等待的所有任务,最后将控制块归还给空白控制块链表。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/889808.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【经验分享】OpenHarmony5.0.0-release编译RK3568不过问题(已解决)

问题描述 根据操作手册正常拉取代码,然后编译OpenHarmony5.0.0版本rk3568项目 编译命令 ./build.sh --product-name rk3568 --ccache出现如下报错 然后真正开始出错的位置是下面这句log FAILED: ../kernel/src_tmp/linux-5.10/boot_linux ../kernel/checkpoint/c…

C++重点和练习-----多态

rpg.cpp: #include <iostream>using namespace std;/*模拟一个游戏场景有一个英雄&#xff1a;初始所有属性为1atk,def,apd,hp游戏当中有以下3种武器长剑Sword&#xff1a; 装备该武器获得 1atx&#xff0c;1def短剑Blade&#xff1a; 装备该武器获得 1atk&#xff0c;1…

Qt之点击鼠标右键创建菜单栏使用(六)

Qt开发 系列文章 - menu&#xff08;六&#xff09; 目录 前言 一、示例演示 二、菜单栏 1.MenuBar 2.Menu 总结 前言 QMainWindow是一个为用户提供主窗口程序的类&#xff0c;包含一个菜单栏&#xff08;menubar&#xff09;、多个工具栏(toolbars)、一个状态栏(status…

天猫魔盒M17/M17S_超级UI 线刷固件包-可救砖(刷机取消双勾)

在智能电视盒子的领域中&#xff0c;天猫魔盒 M17 以其独特魅力占据一席之地&#xff0c;然而&#xff0c;原厂设置有时难以满足进阶用户的多元需求。此刻&#xff0c;刷机成为开启全新体验的关键钥匙&#xff0c;为您的盒子注入鲜活能量。 一、卓越固件特性概览 此款精心打造的…

Elasticsearch 7.x入门学习-Spring Data Elasticsearch框架

1 Spring Data框架 Spring Data 是一个用于简化数据库、非关系型数据库、索引库访问&#xff0c;并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷&#xff0c;并支持 map-reduce 框架和云计算数据服务。 Spring Data 可以极大的简化 JPA的写法&#xff0c;…

【落羽的落羽 C语言篇】一些常见的字符函数、字符串函数、内存函数

文章目录 一、字符函数1. 字符分类函数2. 字符转换函数 二、字符串函数1. strlen的使用和模拟实现使用模拟实现 2. strcpy的使用和模拟实现使用模拟实现 3. strcat的使用和模拟实现使用模拟实现 4. strcmp的使用和模拟实现使用模拟实现 5. strncpy的使用6. strncat的使用7. str…

JAVA:访问者模式(Visitor Pattern)的技术指南

1、简述 访问者模式(Visitor Pattern)是一种行为型设计模式,允许你将操作分离到不同的对象中,而无需修改对象本身的结构。这种模式特别适合复杂对象结构中对其元素进行操作的场景。 本文将介绍访问者模式的核心概念、优缺点,并通过详细代码示例展示如何在实际应用中实现…

小米自研系统Vela全面开源:开启物联网新时代的技术革新之旅

目录 Vela系统的技术特点 1. 高性能与低功耗的完美平衡 2. 高度可扩展性与模块化设计 3. 强大的安全机制 4. 跨平台兼容性 Vela系统的应用场景 1. 智能家居领域 2. 工业物联网领域 3. 医疗健康领域 4. 智慧城市领域 Vela系统的深远影响 1. 推动物联…

Linux/CentOS编译TensorFlow

很多时候为了方便图省事&#xff0c;是通过pip安装TensorFlow的&#xff0c;然而很不幸运行的服务器不支持AVX指令&#xff0c;引入模块的时候会报错&#xff1a; The TensorFlow library was compiled to use AVX instructions, but these aren’t available on your machine.…

2021陇剑杯——流量分析

JWT简介 JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;用于在网络应用环境中以一种紧凑的、URL安全的方式传递声明&#xff08;Claims&#xff09;。JWT通常用于身份验证、信息交换以及验证消息的完整性。JWT通过在不…

visual studio 2022 c++使用教程

介绍 c开发windows一般都是visual studio&#xff0c;linux一般是vscode&#xff0c;但vscode调试c不方便&#xff0c;所以很多情况都是2套代码&#xff0c;在windows上用vs开发方便&#xff0c;在转到linux。 安装 1、官网下载vs2022企业版–选择桌面开发–安装位置–安装–…

Grafana配置告警规则推送企微机器人服务器资源告警

前提 已经部署Grafana&#xff0c;并且dashboard接入数据 大屏编号地址&#xff1a;Node Exporter Full | Grafana Labs 创建企微机器人 备注&#xff1a;群里若有第三方外部人员不能创建 机器人创建完成&#xff0c;记录下来Webhook地址 Grafana配置告警消息模板 {{ define &…

yolov7-搭建及测试

1.环境配置 参考链接&#xff0c;建立环境 2.YOLOv7代码下载 代码及论文地址&#xff1a; GitHub - WongKinYiu/yolov7: Implementation of paper - YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors 下载zip后解压 注意&am…

HCIA-Access V2.5_2_2_2网络通信基础_IP编址与路由

网络层数据封装 首先IP地址封装在网络层&#xff0c;它用于标识一台网络设备&#xff0c;其中IP地址分为两个部分&#xff0c;网络地址和主机地址&#xff0c;通过我们采用点分十进制的形式进行表示。 IP地址分类 对IP地址而言&#xff0c;它细分为五类&#xff0c;A,B,C,D,E,…

信号处理相关的东东(学习解惑)

信号处理相关的东东&#xff08;学习解惑&#xff09; 所有内容学习自知乎专栏&#xff0c;https://www.zhihu.com/column/xinhao&#xff0c;写的很好&#xff0c;值得反复学习 时频域分析的一些常用概念 FROM&#xff1a;https://zhuanlan.zhihu.com/p/35742606 1、相加性…

【cocos creator】按照行列数创建格子布局

调用 this.creatLayout(5, 5, this.boxNode, this.rootNode) //限制数量 this.creatLayout(5, 5, this.boxNode, this.rootNode, cc.v3(0, 0), 10, 10, 23) /*** 创建格子布局* param xCount 列数量* param yCount 行数量* param prefab 预制体* param root 根节点* param root…

WPF 控件

<div id"content_views" class"htmledit_views"><p id"main-toc"><strong>目录</strong></p> WPF基础控件 按钮控件&#xff1a; Button:按钮 RepeatButton:长按按钮 RadioButton:单选按钮 数据显示控件 Te…

java中List集合小练习

题目&#xff1a;将1~100之间所有正整数存放在一个List集合中&#xff0c;并将集合索引位置时10的对象从集合中移除。 代码&#xff1a; import java.util.ArrayList; import java.util.List;public class ListTest {public ListTest(){List<Integer> listnew ArrayLis…

RK3566触摸驱动产品实战 配置设备树 I2C驱动框架(附源码)

引言&#xff1a;相信大家在学完相关驱动框架很少真正的运用在实际的产品案例中&#xff0c;对设备树以及驱动框架还是非常的陌生&#xff0c;其次就是在编写相关驱动还有完成项目任务时的一些思路的引导&#xff0c;这些都是需要补足的&#xff0c;接下来&#xff0c;我们将之…

Qt WORD/PDF(二)使用 QtPdfium库实现 PDF操作、打印等

关于QT Widget 其它文章请点击这里: QT Widget GitHub 源码: QWidgetLearningPro &#xff08;暂未更新&#xff09; 姊妹篇: Qt WORD/PDF&#xff08;一&#xff09;使用 QtPdfium库实现 PDF 预览 一、简介 QtPdfium 是基于Pdfium库的一个Qt绑定。Pdfium是一个…