任务信号量

  在实际任务间的通信中,一个或多个任务发送一个信号量或者消息给另一个任务是比常见的,而一个任务给多个任务发送信号量和消息相对比较少。前面所讲的信号量和消息队列均是单独的内核对象,是独立于任务存在的。这两章要讲述的任务信号量和任务消息队列是
任务特有的属性,紧紧依赖于一个特定任务。

  任务信号量和任务消息队列分别与多值信号量和消息队列非常相似,不同之处是,前者仅发布给一个特定任务,而后者可以发布给多个任务。因此,前者的操作相对比较简单,而且省时。如果任务信号量和任务消息队列可以满足设计需求,那么尽量不要使用普通多值信号量和消息队列

  任务信号量伴随任务存在,只要创建了任务,其任务信号量就是该任务的一个数据成员,任务信号量的数据成员被包含在任务控制块里。
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);                                       //返回信号的当前计数值
}
OSTaskSemPost()

  其实,不管是否使能了中断延迟发布,最终都是调用 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_TaskSemPost()

  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;                                           //直接跳出
    }
}
OS_Post()

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()

  当需要阻塞任务,等待任务信号量时,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
}
OS_Pend()

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()

  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;                                         //不需处理,直接跳出
    }
}
OS_PendAbort()

 

 

转载于:https://www.cnblogs.com/tianxxl/p/10385933.html

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

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

相关文章

域名服务商GoDaddy第四季度扭亏为盈

2月18日消息&#xff0c;据财经网站MarketWatch报道&#xff0c;域名服务提供商GoDaddy周三公布了第四季度财报。公司期内利润与营收均好于预期&#xff0c;给出的营收指导亦符合预测水平。 财报显示&#xff0c;第四季度中GoDaddy营收同比增长14%&#xff0c;为4.254亿美元&am…

devexpress java_DevExpress使用心得一:换肤

最近要用到界面控件DevExpress。一句话&#xff1a;很好很强大&#xff0c;比起VS自带的winform界面&#xff0c;种类和花样要多了不少。然而&#xff0c;强力的功能带来了庞大的信息量&#xff0c;所以我打算通过一些小模块来和大家一起对它进行探讨和研究。今天先研究一下它的…

《低功耗蓝牙开发权威指南》——第3章低功耗蓝牙的体系结构

本节书摘来自华章社区《低功耗蓝牙开发权威指南》一书中的第3章低功耗蓝牙的体系结构&#xff0c;作者 &#xff08;英&#xff09;Robin Heydon&#xff0c;更多章节内容可以访问云栖社区“华章社区”公众号查看 第3章低功耗蓝牙的体系结构专注简单是我一直以来信奉的价值观。…

1970“变种”bug连WiFi热点iOS设备会变砖?

据悉&#xff0c;该漏洞和此前“1970”的bug有关系&#xff0c;但不完全一样。 威锋网讯&#xff0c;你还记得将 iOS 设备系统时间调至 1970.1.1 会让设备变砖的 bug 么&#xff1f;尽管苹果在 iOS 9.3 中已经将这个 bug 修复&#xff0c;但据安全研究员指出&#xff0c;他们发…

基础拾遗------webservice详解

基础拾遗 基础拾遗------特性详解 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗------接口详解 基础拾遗------泛型详解 基础拾遗-----依赖注入 基础拾遗-----数据注解与验证 基础拾遗-----mongoDB操作 基础…

java gc时自动收dump_Full GC分析:设置Java VM参数实现在Full GC前后自动生成Dump

本文讲解了如何设置JavaVM参数实现在FullGC前后自动生成Dump。共有三个VM参数需要设置&#xff1a;HeapDumpBeforeFullGC 实现在Full GC前dump。HeapDumpBeforeFullGC 实现在Full GC后dump。HeapDumpPath 设置Dump保存的路径设置这些参数的方法&#xff0c;这里总结了四种&…

jquery插件dataTables自增序号。

dataTables官网提供了一种方式&#xff0c;使用后没有达到预期效果&#xff08;js报错&#xff09;&#xff0c;没有深究原因。如果需要&#xff0c;可以按照下面的方式来。 1 $(#dataList).dataTable({2 "language": {3 "sProcessing&…

Maven使用详解

1、maven介绍&#xff1a; 2、pom.xml文件理解&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schema…

java web junit_如何使用junit测试javaweb工程

一:创建一个测试类,建议将测试类单独放在一个包中(在 maven 项目里有测试类专门的存放位置),新建一个Junit Test Case类,下一步 测试类的命名建议是你将要测试的类名Test,然后点 Browse, 你可以选择要进行测试的类(一般选择 Service, 因为 Service 关心的是业务需求),用这种方式…

java代码_Java 代码实现排序算法

阅读本文约需要8分钟 大家好&#xff0c;我是你们的导师&#xff0c;我每天都会在这里给大家分享一些干货内容(当然了&#xff0c;周末也要允许老师休息一下哈)。上次老师跟大家分享了下SpringBootGradle MyBatisPlus3.x搭建企业级的后台分离框架的相关知识&#xff0c;今天跟大…

优秀的开源项目C_适合提高C/C++、网络编程能力的开源项目!不要错过,赶紧收藏...

我们学习每一个编程语言都是有一个项目实战的过程&#xff0c;而对于开发类的编程语言&#xff0c;除了适当的做项目程序外&#xff0c;学习了解其他的开源项目更是一个关键&#xff0c;就比如我们的C/C编程语言的学习。前阵子有一个小伙伴就问到我&#xff0c;我学好C/C基础后…

Opencv分水岭算法——watershed自动图像分割用法

分水岭算法是一种图像区域分割法&#xff0c;在分割的过程中&#xff0c;它会把跟临近像素间的相似性作为重要的参考依据&#xff0c;从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓&#xff0c;封闭性是分水岭算法的一个重要特征。 其他图像分割…

Java Annotation

一、了解注释注释是java1.5 jdk这后引入的特性。Java库自己带的注释有Deprecated, Overwrite等。注释是加在类&#xff0c;方法&#xff0c;变量等上的一种标记。并且&#xff0c;可以通过javaj反射操作把这个标记取出来。主要用途是用于对方法&#xff0c;变量&#xff0c;类等…

pycharm显示全部数据_PyCharm第一次安装及使用教程

pycharm简介PyCharm是一种Python IDE&#xff0c;带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具&#xff0c;比如调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制。此外&#xff0c;该IDE提供了一些高级功能&#xff0c;以用…

笔记本win10玩红警黑屏_【买笔记本电脑差评真的有参考意义?】

每次推荐笔记本电脑都会遇到一个重要的问题就是&#xff1a;“大多数消费者会下意识的去看京东评论&#xff0c;参考买的人是怎么说的&#xff0c;往往会出现不懂电脑的人继续误导不懂的人&#xff0c;导致越来越多的人被误导”本文聊聊关于京东评论究竟有没有参考价值。1&…

java前端接收回显图片_图片上传并回显后端篇

图片上传并回显后端篇我们先看一下效果继上一篇的图片上传和回显&#xff0c;我们来实战一下图片上传的整个过程&#xff0c;今天我们将打通前后端&#xff0c;我们来真实的了解一下&#xff0c;我们上传的文件&#xff0c;是以什么样的形式上传到服务器&#xff0c;难道也是一…

zip直链生成网站_手把手教你如何用飞桨自动生成二次元人物头像

【飞桨开发者说】李思佑&#xff0c;昆明理工大学信息与计算科学大四本科生&#xff1b;2018年和2019年两次获得全国大学生数学建模比赛国家二等奖&#xff1b;2020年美国数学建模比赛获M奖。指导老师&#xff1a;昆明理工大学理学院朱志宁想画出独一无二的动漫头像吗&#xff…

Gradle入门到实战(一) — 全面了解Gradle

声明&#xff1a;本文来自汪磊的博客&#xff0c;转载请注明出处 可关注个人公众号&#xff0c;那里更新更及时&#xff0c;阅读体验更好&#xff1a; 友情提示由于文章是从个人公众号拷贝过来整理的&#xff0c;发现图片没有正常显示&#xff0c;没关注公众号的同学可通过如下…

javaweb 图书管理系统完整代码_看一名Java开发人员以红队思维五分钟审计一套代码(续)...

前言上篇文章的发布引起了很多读者的浏览&#xff0c;有很多读者也催更希望读到续集&#xff0c;作者也收获到读者的鼓励&#xff0c;说明这条路线对大家有帮助&#xff0c;是有意义的。所以&#xff0c;今天作者将继续阐述在审计Java代码时的思路。概述上篇文章所讲的SQL注入和…

爱立信数据分析解决方案抓住物联网发展机遇

爱立信在2016年1月6日至9日于美国拉斯维加斯举办的国际消费电子展&#xff08;CES&#xff09;上推出“用户和物联网数据分析”解决方案。该解决方案将能帮助运营商提高对用户和物联网终端的内部管理效率&#xff0c;同时探索跨越多个垂直领域的新型物联网应用。 用户和物联网数…