ucos任務控制塊詳解

2022-07-05 15:42:13 字數 3660 閱讀 4489

ucos實現多工的基礎包括幾個方面:任務控制塊,任務堆疊,中斷,任務優先順序,一一說起

首先,任務控制塊的結構如下

//系統在執行乙個任務的時候,按照任務的優先順序獲取任務控制塊,再在任務堆疊中獲得任務**指標

typedef struct os_tcb os_tcb;

該結構體中有比較多的靠巨集定義開啟的變數,暫時不討論,主要有這幾個比較重要

os_stk          *ostcbstkptr;           /*指向任務堆疊棧頂的指標*/

struct os_tcb   *ostcbnext;             /*指向後乙個任務控制塊的指標 */

struct os_tcb   *ostcbprev;             /*指向前乙個任務控制塊的指標 */

int8u            ostcbprio;             /*任務的優先級別 */

為什麼沒有任務**的指標,這是因為任務**被作業系統存放在了堆疊區中,我們知道,對於任務來說,任務**指標實際上指的是執行這段**的時候,處理器的pc指標,當系統中斷到來的時候,這個指標自動儲存,執行完中斷自動恢復,執行原來的流程,ucos採用的原理就是設計乙個系統級別的中斷,定時的發生該中斷,將執行完中斷並自動恢復的過程修改成為任務切換過程,這個切換過程將我們自己的任務堆疊恢復到cpu實際的堆疊中,自動就能切換到新任務了從而實現多工.可見,任務**指正是應該要放在堆疊中的,後面在針對**說.

另外,作業系統的任務控制塊並不是動態申請的,而是編譯的時候就已經確定有多少個的了,如下

os_ext  os_tcb            ostcbtbl[os_max_tasks + os_n_sys_tasks];   /* table of tcbs */

os_max_tasks和os_n_sys_tasks是靠os_cfg檔案來定義的,前乙個指的是系統最大任務數量,後乙個是系統保留任務數量,系統最多只有這麼些任務控制塊,所以最多最多這麼多工了,同時還有乙個相關聯的全域性變數

os_ext  os_tcb           *ostcbpriotbl[os_lowest_prio + 1u];

這個變數會儲存系統中所有已經設定了的任務控制塊的指標(也就是create了的任務),他的大小是系統最大優先順序決定,ucos不允許優先順序重複的原因就在這裡,他會將系統的任務控制塊按照優先順序的形式存放在這個陣列中,這樣,當切換任務的時候就不需要輪詢任務控制塊列表,而是獲取任務優先順序之後立刻可以在ostcbpriotbl這個表中獲取任務控制塊,效率快很多(不僅僅是快很多的問題,實時系統要求**執行效率是可以預估的,而輪詢鍊錶的時間是不能確定的,可能第一次就找到了,也可能到最後也找不到).

另外還有幾個必備的變數

os_ext  os_tcb   *ostcbcur;    

os_ext  os_tcb   *ostcbfreelist;

os_ext  os_tcb   *ostcbhighrdy; 

os_ext  os_tcb   *ostcblist;   

ostcbcur標識當前著正在執行的tcb塊, ostcbfreelist系統全部tcb中空閒的tcb塊煉表頭指標, ostcbhighrdy當前已經準備好的最高優先順序的tcb塊,下一次切換的目標, ostcblist系統有效tcb塊的煉表頭指標

之前我們看到,在tcb變數結構中有乙個next的指標和乙個prev的指標,這就是用來構造鍊錶的,在系統初始化的時候會開始構造,但是首先我們需要明白乙個事情,不管鍊錶形成了乙個神馬結構,實際的資料元素依然是在ostcbtbl陣列中存放的,只是程式使用的時候組織了乙個鍊錶而已

系統初始化的時候,程式呼叫os_init函式(外部程式設計呼叫),在os_init中呼叫os_inittcblist函式,在os_inittcblist中實現空鍊錶的初始化,如下

static  void  os_inittcblist (void)

ptcb1                   = &ostcbtbl[ix];

ptcb1->ostcbnext        = (os_tcb *)0;                       

#if os_task_name_en > 0u

ptcb1->ostcbtaskname    = (int8u *)(void *)"?";          

#endif

ostcblist               = (os_tcb *)0;                         ostcbfreelist           = &ostcbtbl[0];                }

可以看到,進入這個函式,通過一次迴圈,將ostcbtbl中的全部元素連線成了乙個大的鍊錶,鍊錶的頭為ostcbfreelist,這樣就完成了空任務塊鍊錶的初始化,之後ostcblist賦值為null,等待之後的任務建立

建立任務的時候呼叫的函式為ostaskcreate,我們分析其部分結構

首先,他會經過一番判定,第一,不能在中斷中建立任務 第二,任務優先順序不能重複

if (ostcbpriotbl[prio] == (os_tcb *)0)

前面我們說過,任務建立之後,系統會根據任務的優先順序將其tcb控制塊放到ostcbpriotbl中對應的位置,那麼該位置的資料就會不為0,此時要是檢測到新任務建立的優先順序對應的tcb已經有資料了,說明優先順序重複,不能建立

之後會呼叫兩個函式

ostaskstkinit(task, p_arg, ptos, 0u);

os_tcbinit(prio, psp, (os_stk *)0, 0u, 0u, (void *)0, 0u);

第乙個函式是我們在os_cpu_c.c中需要移植的函式,他和處理器架構相關,具體檢視移植指南,有乙個重點是在ostaskstkinit中的這一句

*(stk)    = (int32u)0x01000000l;             /* xpsrxpsr t 位(第 24 位)置 1 ,否則第一次執行任務時fault*/

*(--stk)  = (int32u)task;                    /* entry pointpc 肯定得指向任務入口*/

將任務的指標存放在了堆疊中,和之前說的吻合

堆疊區設定好了之後就要初始化tcb控制塊,這一段**比較長,說說幾個細節

首先,系統應該從空閒控制塊中取出乙個控制塊並且加入有效tcb控制塊中,如下

ptcb = ostcbfreelist                         

if (ptcb != (os_tcb *)0)

ostcblist               = ptcb;

將當前建立的任務的控制塊指標按照優先順序放到了ostcbpriotbl中,後面直接可以根據優先順序取出來,新的任務控制塊連線到了系統已經存在的任務控制塊的頭部,從而完成了乙個空閒控制塊到有效控制塊的轉移,並建立了任務,等待後期呼叫

另外,ucos定義了乙個空閒任務,用於在沒有任務的情況下執行該任務,所以這個任務必須要是最低優先順序,否則他會搶占別的優先順序的任務,任務函式名

os_taskidle

該任務什麼事情都不幹,在那類似空轉執行,被os_inittaskidle呼叫,而os_inittaskidle被os_init呼叫,從而在初始化系統的時候該任務自動建立

除了空閒任務之外,還定義了乙個統計任務,專用於統計系統執**況,如cpu使用率這些,要監控系統的話,可以再統計任務鉤子函式中做操作將系統運**況輸出,與之相關的變數為oscpuusage

ucos 任務控制塊及任務鍊錶

1 任務控制塊 首先看看ucos中任務控制塊的資料結構為 typedef struct os tcb os tcb 任務控制塊記錄了 任務的堆疊指標,任務當前的執行狀態,任務的優先順序等屬性。其中上面結構中任務狀態 int8u ostcbstat task status 的可取值範圍如下 2 任務控...

UCOS2系統核心講述(三) TCB任務控制塊

寫在前面 ucos2 stm32f1移植詳細過程 彙總文章 ucos2系統核心講述 一 總體描述 ucos2系統核心講述 二 初始化呼叫函式 tcb任務控制塊是用來記錄任務的堆疊指標 任務的當前狀態 任務的優先級別等一些與任務有關屬性的乙個資料結構表 因此,學習本文之前需要了解資料結構 任務控制塊相...

ucos 事件控制塊 及 處理函式

oseventtype ecb型別 有以下幾種 define os event type unused 0 define os event type mbox 1 define os event type q 2 define os event type sem 3 define os event ...