任务信号量

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

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

  任务信号量伴随任务存在,只要创建了任务,其任务信号量就是该任务的一个数据成员,任务信号量的数据成员被包含在任务控制块里。
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…

易于使用的人工智能_需求分析:如何使用这种易于启动的方法+一个案例研究...

易于使用的人工智能by Turgay elik由Turgayelik 需求分析&#xff1a;如何使用这种易于启动的方法一个案例研究 (Requirement Analysis: how to use this startup-friendly approach a case study) In our previous blog posts, we explained why we decided to develop the …

java writeboolean_Java DataOutputStream writeBoolean()方法(带示例)

DataOutputStream类writeBoolean()方法writeBoolean()方法在java.io包中可用。writeBoolean()方法用于将给定的布尔字节写入基本输出流&#xff0c;因此成功执行后写入的变量计数器为1。writeBoolean()方法是一种非静态方法&#xff0c;只能通过类对象访问&#xff0c;如果尝试…

【BZOJ4300】—绝世好题(二进制dp)

传送门 考虑到只需要bi&amp;bi−1̸0b_i\&amp;b_{i-1} \not0bi​&bi−1​̸​0 由于&amp;\&amp;&&#xff0c;我们考虑二进制下只需要一位不为0就可以了f[i]f[i]f[i]表示当前数下&#xff0c;第iii位不为0的最优长度 那就是需要枚举当前这个数所有位就…

爱立信与中国联通成功完成国内首个LTE三载波聚合大规模部署测试

近日&#xff0c;爱立信与中国联通网络技术研究院、联通四川省公司、联通成都市分公司、Qualcomm Incorporated子公司Qualcomm Technologies, Inc.合作成功实现了国内首个三载波聚合大规模部署和运行测试&#xff0c;下行单用户峰值速率达到375Mbps。该项目充分验证了载波聚合大…

七牛服务器入门教程_教程:使用无服务器,StepFunction和StackStorm构建社区的入门应用程序…...

七牛服务器入门教程by Dmitri Zimine由Dmitri Zimine 使用无服务器&#xff0c;StepFunction和StackStorm Exchange构建社区注册应用 (Building a community sign-up app with Serverless, StepFunctions, and StackStorm Exchange) Build a real-world serverless applicatio…

devexpress java_DevExpress使用心得一:换肤

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

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

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

[福建集训2011][LOJ10111]相框

这题主要还是分类讨论欧拉回路 首先对于导线一端没有东西的新建一个节点 由于原图不一定连通所以需要用到并查集判断有多少个连通块 将一条导线连接的两个焊点连接 然后先对于只有一个连通块考虑 1.如果一个焊点是孤立点 它对于导线无影响跳过 2.如果一个焊点度数大于2 它必须被…

TJpgDec—轻量级JPEG解码器

TJpgDec—轻量级JPEG解码器 本文由乌合之众lym瞎编&#xff0c;欢迎转载blog.cnblogs.net/oloroso 下文中解码一词皆由decompression/decompress翻译而来。 TJpgDec是一个为小型嵌入式系统高度优化的创建JPEG图像的解码模块。它工作时占用的内存非常低&#xff0c;以便它可以集…

帮助中心 开源_对开源的贡献帮助我获得了Microsoft的实习机会。 这就是它可以为您提供帮助的方式。

帮助中心 开源“Accomplished X by implementing Y which led to Z.” “通过实现导致Z的Y来完成X。” When I interviewed for software engineering internships this past fall, my open source contributions helped me stand out from the crowd.去年秋天&#xff0c;当我…

java 操作窗口_java selenium (十二) 操作弹出窗口

public static void testMultipleWindowsTitle(WebDriver driver) throws Exception{String url"E:\\StashFolder\\huoli_28hotmail.com\\Stash\\Tank-MoneyProject\\Selenium Webdriver\\AllUIElement.html";driver.get(url);// 获取当前窗口的句柄String parentWin…

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

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

Centos7 安装python3.7.2

下载python3.7.2源码 wget https://www.python.org/ftp/python/3.7.2/Python-3.7.2.tgz 下载完后对压缩包解压缩 tar -xf Python-3.6.3.tgz 进入解压缩完后的文件夹: cd Python-3.7.2 配置&#xff08;需要加上--with-ssl&#xff0c;不然pip不能安装相关函数库&#xff0c;pyt…

华为 9

package NiukeBrush; import java.util.Iterator; //排序与查重 import java.util.LinkedHashSet; import java.util.Scanner; import java.util.Set;//改进做法 public class Huawei9next {public static void main(String[] args) {// TODO Auto-generated method stub//键盘…

印刷点阵字体_印刷术如何确定可读性:衬线与无衬线,以及如何组合字体。

印刷点阵字体by Harshita Arora通过Harshita Arora For digital design, it’s important to know and understand how to use and how to combine different fonts. There’s a font for every mood!对于数字设计&#xff0c;重要的是了解和理解如何使用以及如何组合不同的字…

java中setattribute_浅谈Java web 中request的setAttribute()用法

在两个JSP代码片中有这样两端程序&#xff1a;JSP1代码String [] testnew String[2];test[0]"1";test[1]"2";request.setAttribute("test",test) ;response.sendRedirect("jsp2.jsp");JSP2代码String test[](String[])request.getAttr…

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

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

南京打造大数据创新孵化平台

9月9日上午&#xff0c;南京微软云暨移动应用孵化平台在南京开发区新港高新园揭牌运营&#xff0c;项目创业大赛同步启动。 据悉&#xff0c;南京微软云暨移动应用孵化平台将打造以“云物大智”产业为核心的创新创业孵化平台。平台代理总经理童雪松介绍&#xff0c;平台汇集了强…

react控制组件中元素_React Interview问题:浏览器,组件或元素中呈现了什么?

react控制组件中元素by Samer Buna通过Samer Buna React Interview问题&#xff1a;浏览器&#xff0c;组件或元素中呈现了什么&#xff1f; (React Interview Question: What gets rendered in the browser, a component or an element?) **技巧问题** (** Trick Question *…