μ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.rhkb.cn/news/490956.html

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

相关文章

学习maven(maven 项目模块化,继承,聚合)

前言 本篇博客的核心:理解maven 项目模块化,继承,聚合 的含义 maven 项目模块化 含义 maven项目模块化:使用maven 构建项目,管理项目的方式,我们可以将maven项目根据内在的关系拆分成很多个小项目【模块】…

电工电子技术实验:电压比较器及其应用电路

实验目的 1.了解电压比较器与运算放大器的性能区别; 2.掌握电压比较器的结构及特点; 3.掌握电压比较器电压传输特性的测试方法; 4.学习比较器在电路设计中的应用 实验原理 电压比较器是一…

3D相框案例讲解(详细)

前言 通过现阶段的学习,我们已经掌握了HTML,CSS和JS部分的相关知识点,现在让我们通过一篇案例,来巩固我们近期所学的知识点。 详细视频讲解戳这里 任务一 了解目标案例样式 1.1了解案例 3D相框 1.2 分析案例 首先我们看到一个…

C/C++代码性能优化技巧的书籍及资料

使用C/C开发的场景,大多对代码的执行的速度,实时性有较高的要求,像嵌入式系统的开发,资源还受限。在算力存储空间有限的MCU上写出简洁又高效的代码实际是一种艺术。软件工程师在代码设计上的这种差距,会反映在产品的性…

JAVA:建造者模式(Builder Pattern)的技术指南

1、简述 建造者模式(Builder Pattern)是一种创建型设计模式,它通过将对象的构造过程与表示分离,使得相同的构造过程可以创建不同的表示。建造者模式尤其适用于创建复杂对象的场景。 设计模式样例:https://gitee.com/lhdxhl/design-pattern-example.git 本文将详细介绍建…

软件集成测试内容和作用简析

在现代软件开发过程中,软件集成测试作为关键的一环,日益受到重视。特别是随着信息技术的快速发展,各类软件系统日益庞大复杂,如何确保系统不同模块的顺畅合作,成为了每个项目成功的重要基础。集成测试是指在软件开发过…

Windows 环境实战开源项目GFPGAN 教程

GFPGAN GFPGAN(Generative Facial Prior-GAN)是由腾讯ARC(Applied Research Center)开发的一种实用的真实世界人脸修复算法。它专门设计用于人脸图像的生成和优化,尤其在低质量人脸图像的超分辨率恢复方面表现出色。以…

ctfshow xss

1.web316 看的wp 先在服务器上写一个php文件 <?php$cookie $_GET[cookie];$time date(Y-m-d h:i:s, time());$log fopen("cookie.txt", "a");fwrite($log,$time.: . $cookie . "\n");fclose($log); ?> 获取cookie的值&#xff…

25. 深浅拷贝

一、什么是浅拷贝 只对对象的最顶层进行的拷贝称为 浅拷贝。我们可以用 copy 模块中的 copy() 方法实现浅拷贝。 import copya [11, 22, 33] b [44, 55, 66] c [a, b] d copy.copy(c)print(f"c: {c}") print(f"d: {d}") print(f"c d: {c d}&q…

MySQL追梦旅途之性能优化

1、索引优化 索引可以显著加速查询操作&#xff0c;但过多或不适当的索引也会带来负面影响&#xff08;如增加写入开销&#xff09;。因此&#xff0c;选择合适的索引至关重要。 创建索引&#xff1a; 为经常用于WHERE子句、JOIN条件和ORDER BY排序的列创建索引。 CREATE I…

Liveweb视频汇聚平台支持WebRTC协议赋能H.265视频流畅传输

随着科技的飞速发展和网络技术的不断革新&#xff0c;视频监控已经广泛应用于社会各个领域&#xff0c;成为现代安全管理的重要组成部分。在视频监控领域&#xff0c;视频编码技术的选择尤为重要&#xff0c;它不仅关系到视频的质量&#xff0c;还直接影响到视频的传输效率和兼…

【超详细实战攻略】Jmeter逻辑控制器中if控制器、模块控制器、测试片段的使用方法

【超详细实战攻略】Jmeter逻辑控制器中if控制器、模块控制器、测试片段的使用方法 1 搭建测试对象1.1 禅道下载1.2 禅道安装1.3 运行禅道1.4 接口查看1.5 接口选择 2 Jmeter前置操作2.1 创建Jmeter线程组2.2 创建信息头管理器和请求默认值2.3 添加获取token接口2.4 添加监听器 …

我在广州学 Mysql 系列之 数据类型和运算符详解

ℹ️大家好&#xff0c;我是&#x1f606;练小杰&#xff0c;今天主要学习 Mysql的数据类型以及运算符操作~~ 上周五学习了“Mysql 系列之 数据“表”的基本操作”~ 想要了解更多&#x1f236;️MYSQL 数据库的命令行总结&#xff01;&#xff01;&#xff01; “我是你的敌人,…

如何高效获取Twitter数据:Apify平台上的推特数据采集解决方案

引言 在数据分析和市场研究领域&#xff0c;Twitter&#xff08;现在的X&#xff09;数据一直是重要的信息来源。但是&#xff0c;自从Twitter更改API定价策略后&#xff0c;获取数据的成本大幅提升。本文将介绍一个经济实惠的替代方案。 为什么需要Twitter数据&#xff1f; …

大模型学习笔记------SAM模型详解与思考

大模型学习笔记------SAM模型详解与思考 1、SAM框架概述2、Segment Anything Task3、Segment Anything Model SAM模型是Meta 提出的分割一切模型&#xff08;Segment Anything Model&#xff0c;SAM&#xff09;突破了分割界限&#xff0c;极大地促进了计算机视觉基础模型的发展…

Unity3D仿星露谷物语开发2之工程初始化

1、依赖包安装 进入【Window -> Package Manager】 安装如下插件&#xff1a; 1&#xff09;Cinemachine 它是一套专门控制Unity Camera的模块&#xff0c;适用于各种游戏场景中物体的移动变化&#xff0c;解决了许多关于摄像机间的复杂控制&#xff0c;混合&#xff0c…

[论文阅读] |智能体长期记忆与反思

写在前面&#xff1a;10月份的时候&#xff0c;联发科天玑9400发布&#xff0c;搭载这款旗舰 5G 智能体 AI 芯片的荣耀MagicOS9.0实现了一句话让手机自动操作美团点咖啡。很快商场实体店里便能看到很多品牌手机已经升级为智能体语音助手。下一步&#xff0c;这些智能体或许便能…

数据结构之线性表1

2.1 线性表的定义和基本操作 1.线性结构的特点是&#xff1a;在数据元素的非空有限集中&#xff0c; &#xff08;1&#xff09;存在惟一的一个被称做“第一个”的数据元素&#xff1b; &#xff08;2&#xff09; 存在惟一的一个被称做“最后一个”的数据元素&#xff1b; &a…

【conda/cuda/cudnn/tensorrt】一份简洁的深度学习环境安装清单

&#x1f680;本文主要总结一下conda、cuda、cudnn、tensorrt的快速安装。至于nvidia显卡驱动的安装&#xff0c;暂且不提。本文适合有一定反复安装经验的读者&#x1f602;&#xff0c;方便其快速整理安装思路。 NVIDIA Drivers &#x1f314;01conda ⭐️ 注意&#xff0c;c…

拿到小米 Offer,却迷茫了。。

大家好&#xff0c;我是程序员鱼皮&#xff0c;12 月了&#xff0c;很多小伙伴也拿到了秋招的 Offer&#xff08;没拿到也不要灰心&#xff09;&#xff0c;但即使拿到 Offer&#xff0c;可能还会有一些其他的顾虑。今天分享我们编程导航一位鱼友的提问&#xff0c;给大家作为学…