任務信號量

  在實際任務間的通信中,一個或多個任務發送一個信號量或者消息給另一個任務是比常見的,而一個任務給多個任務發送信號量和消息相對比較少。前面所講的信號量和消息隊列均是單獨的內核對象,是獨立于任務存在的。這兩章要講述的任務信號量和任務消息隊列是
任務特有的屬性,緊緊依賴于一個特定任務。

  任務信號量和任務消息隊列分別與多值信號量和消息隊列非常相似,不同之處是,前者僅發布給一個特定任務,而后者可以發布給多個任務。因此,前者的操作相對比較簡單,而且省時。如果任務信號量和任務消息隊列可以滿足設計需求,那么盡量不要使用普通多值信號量和消息隊列

  任務信號量伴隨任務存在,只要創建了任務,其任務信號量就是該任務的一個數據成員,任務信號量的數據成員被包含在任務控制塊里。
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.pswp.cn/news/395156.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/395156.shtml
英文地址,請注明出處:http://en.pswp.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 *…