在实际任务间的通信中,一个或多个任务发送一个信号量或者消息给另一个任务是比常见的,而一个任务给多个任务发送信号量和消息相对比较少。前面所讲的信号量和消息队列均是单独的内核对象,是独立于任务存在的。这两章要讲述的任务信号量和任务消息队列是
任务特有的属性,紧紧依赖于一个特定任务。
任务信号量和任务消息队列分别与多值信号量和消息队列非常相似,不同之处是,前者仅发布给一个特定任务,而后者可以发布给多个任务。因此,前者的操作相对比较简单,而且省时。如果任务信号量和任务消息队列可以满足设计需求,那么尽量不要使用普通多值信号量和消息队列
任务信号量伴随任务存在,只要创建了任务,其任务信号量就是该任务的一个数据成员,任务信号量的数据成员被包含在任务控制块里。
OSTaskSemPost ()
OSTaskSemPost () 函数用于给一个任务发布任务信号量。OSTaskSemPost () 函数的信息如下表所示。
OSTaskSemPost () 函数的定义也位于“os_task.c”:
S_SEM_CTR OSTaskSemPost (OS_TCB *p_tcb, //目标任务OS_OPT opt, //选项OS_ERR *p_err) //返回错误类型 {OS_SEM_CTR ctr;CPU_TS ts;#ifdef OS_SAFETY_CRITICAL //如果使能(默认禁用)了安全检测if (p_err == (OS_ERR *)0) { //如果 p_err 为空OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数return ((OS_SEM_CTR)0); //返回0(有错误),停止执行 } #endif#if OS_CFG_ARG_CHK_EN > 0u //如果使能(默认使能)了参数检测功能switch (opt) { //根据选项分类处理case OS_OPT_POST_NONE: //如果选项在预期之内case OS_OPT_POST_NO_SCHED:break; //跳出default: //如果选项超出预期*p_err = OS_ERR_OPT_INVALID; //错误类型为“选项非法”return ((OS_SEM_CTR)0u); //返回0(有错误),停止执行 } #endifts = OS_TS_GET(); //获取时间戳#if OS_CFG_ISR_POST_DEFERRED_EN > 0u //如果使能了中断延迟发布if (OSIntNestingCtr > (OS_NESTING_CTR)0) { //如果该函数是在中断中被调用OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_TASK_SIGNAL, //将该信号量发布到中断消息队列(void *)p_tcb,(void *)0,(OS_MSG_SIZE)0,(OS_FLAGS )0,(OS_OPT )0,(CPU_TS )ts,(OS_ERR *)p_err);return ((OS_SEM_CTR)0); //返回0(尚未发布) } #endifctr = OS_TaskSemPost(p_tcb, //将信号量按照普通方式处理 opt,ts,p_err);return (ctr); //返回信号的当前计数值 }
其实,不管是否使能了中断延迟发布,最终都是调用 OS_TaskSemPost() 函数进行发布信号量。只是使能了中断延迟发布的发布过程会比较曲折,中间会有许多插曲,这是中断管理范畴的内容。
OS_TaskSemPost() 函数的定义位于“os_task.c”:
OS_SEM_CTR OS_TaskSemPost (OS_TCB *p_tcb, //目标任务OS_OPT opt, //选项CPU_TS ts, //时间戳OS_ERR *p_err) //返回错误类型 {OS_SEM_CTR ctr;CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和//定义一个局部变量,用于保存关中断前的 CPU 状态寄存器// SR(临界段关中断只需保存SR),开中断时将该值还原。 OS_CRITICAL_ENTER(); //进入临界段if (p_tcb == (OS_TCB *)0) { //如果 p_tcb 为空p_tcb = OSTCBCurPtr; //将任务信号量发给自己(任务) }p_tcb->TS = ts; //记录信号量被发布的时间戳*p_err = OS_ERR_NONE; //错误类型为“无错误”switch (p_tcb->TaskState) { //跟吴目标任务的任务状态分类处理case OS_TASK_STATE_RDY: //如果目标任务没有等待状态case OS_TASK_STATE_DLY:case OS_TASK_STATE_SUSPENDED:case OS_TASK_STATE_DLY_SUSPENDED:switch (sizeof(OS_SEM_CTR)) { //判断是否将导致该信case 1u: //号量计数值溢出,如if (p_tcb->SemCtr == DEF_INT_08U_MAX_VAL) { //果溢出,则开中断,OS_CRITICAL_EXIT(); //返回错误类型为“计*p_err = OS_ERR_SEM_OVF; //数值溢出”,返回0return ((OS_SEM_CTR)0); //(有错误),不继续} //执行。break; case 2u:if (p_tcb->SemCtr == DEF_INT_16U_MAX_VAL) {OS_CRITICAL_EXIT();*p_err = OS_ERR_SEM_OVF;return ((OS_SEM_CTR)0);}break;case 4u:if (p_tcb->SemCtr == DEF_INT_32U_MAX_VAL) {OS_CRITICAL_EXIT();*p_err = OS_ERR_SEM_OVF;return ((OS_SEM_CTR)0);}break;default:break;}p_tcb->SemCtr++; //信号量计数值不溢出则加1ctr = p_tcb->SemCtr; //获取信号量的当前计数值OS_CRITICAL_EXIT(); //退出临界段break; //跳出case OS_TASK_STATE_PEND: //如果任务有等待状态case OS_TASK_STATE_PEND_TIMEOUT:case OS_TASK_STATE_PEND_SUSPENDED:case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:if (p_tcb->PendOn == OS_TASK_PEND_ON_TASK_SEM) { //如果正等待任务信号量OS_Post((OS_PEND_OBJ *)0, //发布信号量给目标任务(OS_TCB *)p_tcb,(void *)0,(OS_MSG_SIZE )0u,(CPU_TS )ts);ctr = p_tcb->SemCtr; //获取信号量的当前计数值OS_CRITICAL_EXIT_NO_SCHED(); //退出临界段(无调度)if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) { //如果选择了调度任务OSSched(); //调度任务 }} else { //如果没等待任务信号量switch (sizeof(OS_SEM_CTR)) { //判断是否将导致case 1u: //该信号量计数值if (p_tcb->SemCtr == DEF_INT_08U_MAX_VAL) { //溢出,如果溢出,OS_CRITICAL_EXIT(); //则开中断,返回*p_err = OS_ERR_SEM_OVF; //错误类型为“计return ((OS_SEM_CTR)0); //数值溢出”,返} //回0(有错误),break; //不继续执行。case 2u:if (p_tcb->SemCtr == DEF_INT_16U_MAX_VAL) {OS_CRITICAL_EXIT();*p_err = OS_ERR_SEM_OVF;return ((OS_SEM_CTR)0);}break;case 4u:if (p_tcb->SemCtr == DEF_INT_32U_MAX_VAL) {OS_CRITICAL_EXIT();*p_err = OS_ERR_SEM_OVF;return ((OS_SEM_CTR)0);}break;default:break;}p_tcb->SemCtr++; //信号量计数值不溢出则加1ctr = p_tcb->SemCtr; //获取信号量的当前计数值OS_CRITICAL_EXIT(); //退出临界段 }break; //跳出default: //如果任务状态超出预期OS_CRITICAL_EXIT(); //退出临界段*p_err = OS_ERR_STATE_INVALID; //错误类型为“状态非法”ctr = (OS_SEM_CTR)0; //清零 ctrbreak; //跳出 }return (ctr); //返回信号量的当前计数值 }
在 OS_SemPost() 函数中,又会调用 OS_Post() 函数发布内核对象。OS_Post() 函数是一个底层的发布函数,它不仅仅用来发布任务信号量,还可以发布多值信号量、互斥信号量、消息队列、事件标志组或任务消息队列。注意,在这里,OS_Post() 函数将任务信号量直接发布给目标任务。
OS_Post() 函数的定义位于“os_core.c”。:
void OS_Post (OS_PEND_OBJ *p_obj, //内核对象类型指针OS_TCB *p_tcb, //任务控制块void *p_void, //消息OS_MSG_SIZE msg_size, //消息大小CPU_TS ts) //时间戳 {switch (p_tcb->TaskState) { //根据任务状态分类处理case OS_TASK_STATE_RDY: //如果任务处于就绪状态case OS_TASK_STATE_DLY: //如果任务处于延时状态case OS_TASK_STATE_SUSPENDED: //如果任务处于挂起状态case OS_TASK_STATE_DLY_SUSPENDED: //如果任务处于延时中被挂起状态break; //不用处理,直接跳出case OS_TASK_STATE_PEND: //如果任务处于无期限等待状态case OS_TASK_STATE_PEND_TIMEOUT: //如果任务处于有期限等待状态if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) { //如果任务在等待多个信号量或消息队列OS_Post1(p_obj, //标记哪个内核对象被发布 p_tcb,p_void,msg_size,ts);} else { //如果任务不是在等待多个信号量或消息队列 #if (OS_MSG_EN > 0u) //如果使能了任务队列或消息队列p_tcb->MsgPtr = p_void; //保存消息到等待任务p_tcb->MsgSize = msg_size; #endifp_tcb->TS = ts; //保存时间戳到等待任务 }if (p_obj != (OS_PEND_OBJ *)0) { //如果内核对象为空OS_PendListRemove(p_tcb); //从等待列表移除该等待任务 #if OS_CFG_DBG_EN > 0u //如果使能了调试代码和变量 OS_PendDbgNameRemove(p_obj, //移除内核对象的调试名 p_tcb); #endif}OS_TaskRdy(p_tcb); //让该等待任务准备运行p_tcb->TaskState = OS_TASK_STATE_RDY; //任务状态改为就绪状态p_tcb->PendStatus = OS_STATUS_PEND_OK; //清除等待状态p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; //标记不再等待break;case OS_TASK_STATE_PEND_SUSPENDED: //如果任务在无期限等待中被挂起case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: //如果任务在有期限等待中被挂起if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) { //如果任务在等待多个信号量或消息队列OS_Post1(p_obj, //标记哪个内核对象被发布 p_tcb,p_void,msg_size,ts);} else { //如果任务不在等待多个信号量或消息队列 #if (OS_MSG_EN > 0u) //如果使能了调试代码和变量p_tcb->MsgPtr = p_void; //保存消息到等待任务p_tcb->MsgSize = msg_size; #endifp_tcb->TS = ts; //保存时间戳到等待任务 }OS_TickListRemove(p_tcb); //从节拍列表移除该等待任务if (p_obj != (OS_PEND_OBJ *)0) { //如果内核对象为空OS_PendListRemove(p_tcb); //从等待列表移除该等待任务 #if OS_CFG_DBG_EN > 0u //如果使能了调试代码和变量 OS_PendDbgNameRemove(p_obj, //移除内核对象的调试名 p_tcb); #endif}p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; //任务状态改为被挂起状态p_tcb->PendStatus = OS_STATUS_PEND_OK; //清除等待状态p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; //标记不再等待break;default: //如果任务状态超出预期break; //直接跳出 } }
OSTaskSemPend ()
与 OSSemPost () 多值信号量发布函数相对应,OSTaskSemPend () 函数用于等待任务信号量。
OSTaskSemPend () 函数的定义也位于“os_task.c:
OS_SEM_CTR OSTaskSemPend (OS_TICK timeout, //等待超时时间OS_OPT opt, //选项CPU_TS *p_ts, //返回时间戳OS_ERR *p_err) //返回错误类型 {OS_SEM_CTR ctr;CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和//定义一个局部变量,用于保存关中断前的 CPU 状态寄存器// SR(临界段关中断只需保存SR),开中断时将该值还原。 #ifdef OS_SAFETY_CRITICAL //如果使能了安全检测if (p_err == (OS_ERR *)0) { //如果错误类型实参为空OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数return ((OS_SEM_CTR)0); //返回0(有错误),停止执行 } #endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u //如果使能了中断中非法调用检测if (OSIntNestingCtr > (OS_NESTING_CTR)0) { //如果该函数在中断中被调用*p_err = OS_ERR_PEND_ISR; //返回错误类型为“在中断中等待”return ((OS_SEM_CTR)0); //返回0(有错误),停止执行 } #endif#if OS_CFG_ARG_CHK_EN > 0u //如果使能了参数检测switch (opt) { //根据选项分类处理case OS_OPT_PEND_BLOCKING: //如果选项在预期内case OS_OPT_PEND_NON_BLOCKING:break; //直接跳出default: //如果选项超出预期*p_err = OS_ERR_OPT_INVALID; //错误类型为“选项非法”return ((OS_SEM_CTR)0); //返回0(有错误),停止执行 } #endifif (p_ts != (CPU_TS *)0) { //如果 p_ts 非空*p_ts = (CPU_TS )0; //清零(初始化)p_ts }CPU_CRITICAL_ENTER(); //关中断 if (OSTCBCurPtr->SemCtr > (OS_SEM_CTR)0) { //如果任务信号量当前可用OSTCBCurPtr->SemCtr--; //信号量计数器减1ctr = OSTCBCurPtr->SemCtr; //获取信号量的当前计数值if (p_ts != (CPU_TS *)0) { //如果 p_ts 非空*p_ts = OSTCBCurPtr->TS; //返回信号量被发布的时间戳 } #if OS_CFG_TASK_PROFILE_EN > 0u //如果使能了任务控制块的简况变量OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS; //更新任务等待if (OSTCBCurPtr->SemPendTimeMax < OSTCBCurPtr->SemPendTime) { //任务信号量的OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime; //最长时间记录。 } #endifCPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_NONE; //错误类型为“无错误”return (ctr); //返回信号量的当前计数值 }/* 如果任务信号量当前不可用 */if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { //如果选择了不阻塞任务CPU_CRITICAL_EXIT(); //开中断*p_err = OS_ERR_PEND_WOULD_BLOCK; //错误类型为“缺乏阻塞”return ((OS_SEM_CTR)0); //返回0(有错误),停止执行} else { //如果选择了阻塞任务if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { //如果调度器被锁CPU_CRITICAL_EXIT(); //开中断*p_err = OS_ERR_SCHED_LOCKED; //错误类型为“调度器被锁”return ((OS_SEM_CTR)0); //返回0(有错误),停止执行 }}/* 如果调度器未被锁 */OS_CRITICAL_ENTER_CPU_EXIT(); //锁调度器,重开中断 OS_Pend((OS_PEND_DATA *)0, //阻塞任务,等待信号量。(OS_PEND_OBJ *)0, //不需插入等待列表。 (OS_STATE )OS_TASK_PEND_ON_TASK_SEM,(OS_TICK )timeout);OS_CRITICAL_EXIT_NO_SCHED(); //开调度器(无调度) OSSched(); //调度任务/* 任务获得信号量后得以继续运行 */CPU_CRITICAL_ENTER(); //关中断switch (OSTCBCurPtr->PendStatus) { //根据任务的等待状态分类处理case OS_STATUS_PEND_OK: //如果任务成功获得信号量if (p_ts != (CPU_TS *)0) { //返回信号量被发布的时间戳*p_ts = OSTCBCurPtr->TS; #if OS_CFG_TASK_PROFILE_EN > 0u //更新最长等待时间记录OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS;if (OSTCBCurPtr->SemPendTimeMax < OSTCBCurPtr->SemPendTime) {OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime;} #endif}*p_err = OS_ERR_NONE; //错误类型为“无错误”break; //跳出case OS_STATUS_PEND_ABORT: //如果等待被中止if (p_ts != (CPU_TS *)0) { //返回被终止时的时间戳*p_ts = OSTCBCurPtr->TS;}*p_err = OS_ERR_PEND_ABORT; //错误类型为“等待被中止”break; //跳出case OS_STATUS_PEND_TIMEOUT: //如果等待超时if (p_ts != (CPU_TS *)0) { //返回时间戳为0*p_ts = (CPU_TS )0;}*p_err = OS_ERR_TIMEOUT; //错误类型为“等待超时”break; //跳出default: //如果等待状态超出预期*p_err = OS_ERR_STATUS_INVALID; //错误类型为“状态非法”break; //跳出 } ctr = OSTCBCurPtr->SemCtr; //获取信号量的当前计数值CPU_CRITICAL_EXIT(); //开中断return (ctr); //返回信号量的当前计数值 }
当需要阻塞任务,等待任务信号量时,OSTaskSemPend () 函数会调用一个更加底层的等待函数来执行当前任务对多值信号量的等待,该函数就是 OS_Pend()。与 OS_Post() 函数一样,OS_Pend() 函数不仅仅用来等待任务信号量,还可以等待多值信号量、互斥信号量、消息队列、事件标志组或任务消息队列。注意,在这里,OS_Pend()函数并没有把当前任务插入到等待列表。
OS_Pend() 函数的定义位于“os_core.c”:
void OS_Pend (OS_PEND_DATA *p_pend_data, //待插入等待列表的元素OS_PEND_OBJ *p_obj, //等待的内核对象OS_STATE pending_on, //等待哪种对象内核OS_TICK timeout) //等待期限 {OS_PEND_LIST *p_pend_list;OSTCBCurPtr->PendOn = pending_on; //资源不可用,开始等待OSTCBCurPtr->PendStatus = OS_STATUS_PEND_OK; //正常等待中 OS_TaskBlock(OSTCBCurPtr, //阻塞当前运行任务,timeout); //如果 timeout 非0,把任务插入的节拍列表if (p_obj != (OS_PEND_OBJ *)0) { //如果等待对象非空p_pend_list = &p_obj->PendList; //获取对象的等待列表到 p_pend_listp_pend_data->PendObjPtr = p_obj; //保存要等待的对象OS_PendDataInit((OS_TCB *)OSTCBCurPtr, //初始化 p_pend_data(待插入等待列表)(OS_PEND_DATA *)p_pend_data,(OS_OBJ_QTY )1);OS_PendListInsertPrio(p_pend_list, //按优先级将 p_pend_data 插入到等待列表 p_pend_data);} else { //如果等待对象为空OSTCBCurPtr->PendDataTblEntries = (OS_OBJ_QTY )0; //清零当前任务的等待域数据OSTCBCurPtr->PendDataTblPtr = (OS_PEND_DATA *)0; } #if OS_CFG_DBG_EN > 0u //如果使能了调试代码和变量 OS_PendDbgNameAdd(p_obj, //更新信号量的 DbgNamePtr 元素为其等待OSTCBCurPtr); //列表中优先级最高的任务的名称。 #endif }
OSTaskSemPendAbort ()
OSTaskSemPendAbort() 函数用于中止一个任务对其任务信号量的等待。要使用OSTaskSemPendAbort() 函数,还得事先使能 OS_CFG_TASK_SEM_PEND_ABORT_EN(位于“os_cfg.h”)
#define OS_CFG_TASK_SEM_PEND_ABORT_EN 1u //使能/禁用函数 OSTaskSemPendAbort()
OSTaskSemPendAbort() 函数的信息如下表所示。
OSTaskSemPendAbort() 函数的定义位于“os_task.c”:
#if OS_CFG_TASK_SEM_PEND_ABORT_EN > 0u //如果使能了 OSTaskSemPendAbort() CPU_BOOLEAN OSTaskSemPendAbort (OS_TCB *p_tcb, //目标任务OS_OPT opt, //选项OS_ERR *p_err) //返回错误类型 {CPU_TS ts;CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和//定义一个局部变量,用于保存关中断前的 CPU 状态寄存器// SR(临界段关中断只需保存SR),开中断时将该值还原。 #ifdef OS_SAFETY_CRITICAL //如果使能了安全检测if (p_err == (OS_ERR *)0) { //如果错误类型实参为空OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数return (DEF_FALSE); //返回(失败),停止执行 } #endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u //如果使能了中断中非法调用检测if (OSIntNestingCtr > (OS_NESTING_CTR)0) { //如果该函数是在中断中被调用*p_err = OS_ERR_PEND_ABORT_ISR; //错误类型为“在中断中创建对象”return (DEF_FALSE); //返回(失败),停止执行 } #endif#if OS_CFG_ARG_CHK_EN > 0u //如果使能了参数检测switch (opt) { //根据选项匪类处理case OS_OPT_POST_NONE: //如果选项在预期内case OS_OPT_POST_NO_SCHED:break; //直接跳出default: //如果选项超出预期*p_err = OS_ERR_OPT_INVALID; //错误类型为“选项非法”return (DEF_FALSE); //返回(失败),停止执行 } #endifCPU_CRITICAL_ENTER(); //关中断if ((p_tcb == (OS_TCB *)0) || //如果 p_tcb 为空,或者(p_tcb == OSTCBCurPtr)) { //p_tcb 指向当前运行任务。CPU_CRITICAL_EXIT(); //开中断*p_err = OS_ERR_PEND_ABORT_SELF; //错误类型为“中止自身”return (DEF_FALSE); //返回(失败),停止执行 }/* 如果 p_tcb (目标任务) 不是当前运行任务(自身) */if (p_tcb->PendOn != OS_TASK_PEND_ON_TASK_SEM) { //如果目标任务没在等待任务信号量CPU_CRITICAL_EXIT(); //开中断*p_err = OS_ERR_PEND_ABORT_NONE; //错误类型为“没在等待任务信号量”return (DEF_FALSE); //返回(失败),停止执行 }CPU_CRITICAL_EXIT(); //开中断 OS_CRITICAL_ENTER(); //进入临界段ts = OS_TS_GET(); //获取时间戳OS_PendAbort((OS_PEND_OBJ *)0, //中止目标任务对信号量的等待 p_tcb, ts);OS_CRITICAL_EXIT_NO_SCHED(); //退出临界段(无调度)if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) { //如果选择了任务调度OSSched(); //调度任务 }*p_err = OS_ERR_NONE; //错误类型为“无错误”return (DEF_TRUE); //返回(中止成功) } #endif
OSTaskSemPendAbort() 函数会调用一个更加底层的中止等待函数来执行当前任务对多值信号量的等待,该函数就是 OS_PendAbort()。OS_PendAbort() 函数不仅仅用来中止对任务信号量的等待,还可以中止对多值信号量、互斥信号量、消息队列、事件标志组或任务消息队列的等待。
OS_PendAbort() 函数的定义位于“os_core.c”:
void OS_PendAbort (OS_PEND_OBJ *p_obj, //被等待对象的类型OS_TCB *p_tcb, //任务控制块指针CPU_TS ts) //等待被中止时的时间戳 {switch (p_tcb->TaskState) { //根据任务状态分类处理 case OS_TASK_STATE_RDY: //如果任务是就绪状态case OS_TASK_STATE_DLY: //如果任务是延时状态case OS_TASK_STATE_SUSPENDED: //如果任务是挂起状态case OS_TASK_STATE_DLY_SUSPENDED: //如果任务是在延时中被挂起break; //这些情况均与等待无关,直接跳出case OS_TASK_STATE_PEND: //如果任务是无期限等待状态case OS_TASK_STATE_PEND_TIMEOUT: //如果任务是有期限等待状态if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) { //如果任务在等待多个信号量或消息队列OS_PendAbort1(p_obj, //强制解除任务对某一对象的等待 p_tcb,ts);} #if (OS_MSG_EN > 0u) //如果使能了任务队列或消息队列p_tcb->MsgPtr = (void *)0; //清除(复位)任务的消息域p_tcb->MsgSize = (OS_MSG_SIZE)0u; #endifp_tcb->TS = ts; //保存等待被中止时的时间戳到任务控制块if (p_obj != (OS_PEND_OBJ *)0) { //如果等待对象非空OS_PendListRemove(p_tcb); //将任务从所有等待列表中移除 }OS_TaskRdy(p_tcb); //让任务进准备运行p_tcb->TaskState = OS_TASK_STATE_RDY; //修改任务状态为就绪状态p_tcb->PendStatus = OS_STATUS_PEND_ABORT; //标记任务的等待被中止p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; //标记任务目前没有等待任何对象break; //跳出case OS_TASK_STATE_PEND_SUSPENDED: //如果任务在无期限等待中被挂起case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: //如果任务在有期限等待中被挂起if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) { //如果任务在等待多个信号量或消息队列OS_PendAbort1(p_obj, //强制解除任务对某一对象的等待 p_tcb,ts);} #if (OS_MSG_EN > 0u) //如果使能了任务队列或消息队列p_tcb->MsgPtr = (void *)0; //清除(复位)任务的消息域p_tcb->MsgSize = (OS_MSG_SIZE)0u; #endifp_tcb->TS = ts; //保存等待被中止时的时间戳到任务控制块if (p_obj != (OS_PEND_OBJ *)0) { //如果等待对象非空OS_PendListRemove(p_tcb); //将任务从所有等待列表中移除 }OS_TickListRemove(p_tcb); //让任务脱离节拍列表p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; //修改任务状态为挂起状态p_tcb->PendStatus = OS_STATUS_PEND_ABORT; //标记任务的等待被中止p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; //标记任务目前没有等待任何对象break; //跳出default: //如果任务状态超出预期break; //不需处理,直接跳出 } }