1. 程式人生 > >uC/OS-III之任務訊號量

uC/OS-III之任務訊號量

1.給任務釋出訊號量是一種非常常用的同步方法,因此,在uC/OS-III中,每個任務都有它自己的內嵌訊號量。

2.當建立任務時,任務訊號量會被自動建立,且初始計數為零。

3.等待任務訊號量使用函式OSTaskSemPend(),它的定義位於os_task.c中。

OS_SEM_CTR  OSTaskSemPend (OS_TICK   timeout,                // 1190行 - 1293行,超時時間
                           OS_OPT    opt,                    // 等待的方式
                           CPU_TS   *
p_ts, // 時間戳 OS_ERR *p_err) // 錯誤碼 { OS_SEM_CTR ctr; CPU_SR_ALLOC(); // 宣告變數cpu_sr,用來臨時儲存CPU的狀態暫存器 #ifdef OS_SAFETY_CRITICAL // 允許進行系統安全性檢查 if (p_err == (OS_ERR *
)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return ((OS_SEM_CTR)0); } #endif #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u // 允許進行ISR呼叫檢查 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { // 不允許在ISR中呼叫 *p_err = OS_ERR_PEND_ISR; return ((OS_SEM_CTR)0
); } #endif if (p_ts != (CPU_TS *)0) { *p_ts = (CPU_TS )0; // 初始化返回的時間戳 } CPU_CRITICAL_ENTER(); // 進入臨界區 if (OSTCBCurPtr->SemCtr > (OS_SEM_CTR)0) { // 計數值 > 0,表示訊號量可用 OSTCBCurPtr->SemCtr--; // 計數值減1 ctr = OSTCBCurPtr->SemCtr; 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->SemPendTime > OSTCBCurPtr->SemPendTimeMax) { OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime; } #endif CPU_CRITICAL_EXIT(); // 退出臨界區 *p_err = OS_ERR_NONE; return (ctr); } // 計數值 == 0,訊號量不可用 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); } else { // 阻塞型 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { // 任務排程器鎖定,無法掛起任務 CPU_CRITICAL_EXIT(); // 退出臨界區 *p_err = OS_ERR_SCHED_LOCKED; return ((OS_SEM_CTR)0); } } OS_CRITICAL_ENTER_CPU_CRITICAL_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->SemPendTime > OSTCBCurPtr->SemPendTimeMax) { 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) { *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); }

4.釋出任務訊號量使用OSTaskSemPost(),它的定義位於os_task.c中。

OS_SEM_CTR  OSTaskSemPost (OS_TCB  *p_tcb,                  // 1401行 - 1439行
                           OS_OPT   opt,                    // 釋出任務訊號量的方式
                           OS_ERR  *p_err)
{
    OS_SEM_CTR  ctr;
    CPU_TS      ts;

#ifdef OS_SAFETY_CRITICAL                                   // 允許進行系統安全性檢查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_SEM_CTR)0);
    }
#endif

    ts = OS_TS_GET();                                       // 獲取時間戳

#if OS_CFG_ISR_POST_DEFERRED_EN > 0u                        // 延遲釋出模式
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 檢視是否是在ISR中呼叫該函式
        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);
    }
#endif
    ctr = OS_TaskSemPost(p_tcb,                             // 釋出訊號量
                         opt,
                         ts,
                         p_err);
    return (ctr);
}

釋出任務訊號量的方式有以下兩種:
OS_OPT_POST_NONE表明釋出任務訊號量之後呼叫排程程式;
OS_OPT_POST_NO_SCHED表明在OSTaskSemPost()的末尾不會呼叫排程程式。

5.任務訊號量做雙向同步時,不能用於任務和ISR之間的同步,因為ISR不能等待訊號量。