在實際任務間的通信中,一個或多個任務發送一個信號量或者消息給另一個任務是比常見的,而一個任務給多個任務發送信號量和消息相對比較少。前面所講的信號量和消息隊列均是單獨的內核對象,是獨立于任務存在的。這兩章要講述的任務信號量和任務消息隊列是
任務特有的屬性,緊緊依賴于一個特定任務。
任務信號量和任務消息隊列分別與多值信號量和消息隊列非常相似,不同之處是,前者僅發布給一個特定任務,而后者可以發布給多個任務。因此,前者的操作相對比較簡單,而且省時。如果任務信號量和任務消息隊列可以滿足設計需求,那么盡量不要使用普通多值信號量和消息隊列
任務信號量伴隨任務存在,只要創建了任務,其任務信號量就是該任務的一個數據成員,任務信號量的數據成員被包含在任務控制塊里。
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
總結
以上是生活随笔為你收集整理的任务信号量的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。