新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > μC/OS-II的任務管理

        μC/OS-II的任務管理

        作者: 時間:2016-10-08 來源:網絡 收藏

        圖 F4.1 內存碎片

        μC/OS-Ⅱ支持的處理器的堆棧既可以從上(高地址)往下(低地址)長也可以從下往上長(參看4.02,任務堆棧)。用戶在調用OSTaskCreate()或OSTaskCreateExt()的時候必須知道堆棧是怎樣長的,因為用戶必須得把堆棧的棧頂傳遞給以上兩個函數,當OS_CPU.H文件中的OS_STK_GROWTH置為0時,用戶需要將堆棧的最低內存地址傳遞給任務創建函數,如程序清單4.7所示。

        程序清單 L4.7 堆棧從下往上遞增

        OS_STKTaskStack[TASK_STACK_SIZE];

        OSTaskCreate(task,pdata,TaskStack[0],prio);

        當OS_CPU.H文件中的OS_STK_GROWTH置為1時,用戶需要將堆棧的最高內存地址傳遞給任務創建函數,如程序清單4.8所示。

        程序清單 L4.8 堆棧從上往下遞減

        OS_STKTaskStack[TASK_STACK_SIZE];

        OSTaskCreate(task,pdata,TaskStack[TASK_STACK_SIZE-1],prio);

        這個問題會影響代碼的可移植性。 如果用戶想將代碼從支持往下遞減堆棧的處理器中移植到支持往上遞增堆棧的處理器中的話,用戶得使代碼同時適應以上兩種情況。在這種特殊情況下,程序清單L4.7和4.8可重新寫成如程序清單L4.9所示的形式。

        程序清單 L4.9 對兩個方向增長的堆棧都提供支持

        OS_STKTaskStack[TASK_STACK_SIZE];

        #ifOS_STK_GROWTH==0

        OSTaskCreate(task,pdata,TaskStack[0],prio);

        #else

        OSTaskCreate(task,pdata,TaskStack[TASK_STACK_SIZE-1],prio);

        #endif

        任務所需的堆棧的容量是由應用程序指定的。 用戶在指定堆棧大小的時候必須考慮用戶的任務所調用的所有函數的嵌套情況,任務所調用的所有函數會分配的局部變量的數目,以及所有可能的中斷服務例程嵌套的堆棧需求。另外,用戶的堆棧必須能儲存所有的CPU寄存器。

        4.3 堆棧檢驗,OSTaskStkChk()

        有時候決定任務實際所需的堆棧空間大小是很有必要的。因為這樣用戶就可以避免為任務分配過多的堆棧空間,從而減少自己的應用程序代碼所需的RAM(內存)數量。μC/OS-Ⅱ提供的OSTaskStkChk()函數可以為用戶提供這種有價值的信息。

        在圖4.2中,筆者假定堆棧是從上往下遞減的(即OS_STK_GROWTH被置為1),但以下的討論也同樣適用于從下往上長的堆棧[F4.2(1)]。μC/OS-Ⅱ是通過查看堆棧本身的內容來決定堆棧的方向的。只有內核或是任務發出堆棧檢驗的命令時,堆棧檢驗才會被執行,它不會自動地去不斷檢驗任務的堆棧使用情況。在堆棧檢驗時,μC/OS-Ⅱ要求在任務建立的時候堆棧中存儲的必須是0值(即堆棧被清零)[F4.2(2)]。另外,μC/OS-Ⅱ還需要知道堆棧棧底(BOS)的位置和分配給任務的堆棧的大小[F4.2(2)]。在任務建立的時候,BOS的位置及堆棧的這兩個值儲存在任務的OS_TCB中。

        為了使用μC/OS-Ⅱ的堆棧檢驗功能,用戶必須要做以下幾件事情:

        z 在OS_CFG.H文件中設OS_TASK_CREATE_EXT為1。

        z 用OSTaskCreateExt()建立任務,并給予任務比實際需要更多的內存空間。

        z 在OSTaskCreateExt()中, 將參數opt設置為OS_TASK_OPT_STK_CHK+OS_TASK_OPT_STK_CLR。注意如果用戶的程序啟動代碼清除了所有的RAM,并且從未刪除過已建立了的任務,那么用戶就不必設置選項OS_TASK_OPT_STK_CLR了。這樣就會減少OSTaskCreateExt()的執行時間。

        z 將用戶想檢驗的任務的優先級作為OSTaskStkChk()的參數并調用之。

        圖 4.2 堆棧檢驗

        OSTaskStkChk()順著堆棧的棧底開始計算空閑的堆棧空間大小, 具體實現方法是統計儲存值為0的連續堆棧入口的數目,直到發現儲存值不為0的堆棧入口[F4.2(5)]。注意堆棧入口的儲存值在進行檢驗時使用的是堆棧的數據類型(參看OS_CPU.H中的OS_STK)。換句話說,如果堆棧的入口有32位寬,對0值的比較也是按32位完成的。所用的堆棧的空間大小是指從用戶在OSTaskCreateExt()中定義的堆棧大小中減去了儲存值為0的連續堆棧入口以后的大小。OSTaskStkChk()實際上把空閑堆棧的字節數和已用堆棧的字節數放置在0S_STK_DATA數據結構中(參看μCOS_Ⅱ.H)。注意在某個給定的時間,被檢驗的任務的堆棧指針可能會指向最初的堆棧棧頂(TOS)與堆棧最深處之間的任何位置[F4.2(7)]。 每次在調用OSTaskStkChk()的時候, 用戶也可能會因為任務還沒觸及堆棧的最深處而得到不同的堆棧的空閑空間數。

        用戶應該使自己的應用程序運行足夠長的時間,并且經歷最壞的堆棧使用情況,這樣才能得到正確的數。一旦OSTaskStkChk()提供給用戶最壞情況下堆棧的需求,用戶就可以重新設置堆棧的最后容量了。為了適應系統以后的升級和擴展,用戶應該多分配10%-100%的堆棧空間。在堆棧檢驗中,用戶所得到的只是一個大致的堆棧使用情況,并不能說明堆棧使用的全部實際情況。

        OSTaskStkChk()函數的代碼如程序清單L4.10所示。0S_STK_DATA(參看μCOS_Ⅱ.H)數據結構用來保存有關任務堆棧的信息。筆者打算用一個數據結構來達到兩個目的。第一,把OSTaskStkChk()當作是查詢類型的函數,并且使所有的查詢函數用同樣的方法返回,即返回查詢數據到某個數據結構中。第二,在數據結構中傳遞數據使得筆者可以在不改變OSTaskStkChk()的API(應用程序編程接口)的條件下為該數據結構增加其它域,從而擴展OSTaskStkChk()的功能。現在,0S_STK_DATA只包含兩個域:OSFree和OSUsed。從代碼中用戶可看到,通過指定執行堆棧檢驗的任務的優先級可以調用OSTaskStkChk()。如果用戶指定0S_PRIO_SELF[L4.10(1)],那么就表明用戶想知道當前任務的堆棧信息。當然,前提是任務已經存在[L4.10(2)]。要執行堆棧檢驗,用戶必須已用OSTaskCreateExt()建立了任務并且已經傳遞了選項OS_TASK_OPT_CHK[L4.10(3)]。如果所有的條件都滿足了,OSTaskStkChk()就會象前面描述的那樣從堆棧棧底開始統計堆棧的空閑空間[L4.10(4)]。 最后,儲存在0S_STK_DATA中的信息就被確定下來了[L4.10(5)]。注意函數所確定的是堆棧的實際空閑字節數和已被占用的字節數,而不是堆棧的總字節數。當然,堆棧的實際大小(用



        關鍵詞:

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 巩义市| 安庆市| 综艺| 双城市| 南涧| 开平市| 苏尼特右旗| 新巴尔虎左旗| 方正县| 临湘市| 阿城市| 河南省| 尉氏县| 峨眉山市| 林芝县| 汉阴县| 保山市| 溆浦县| 新邵县| 开封市| 额尔古纳市| 云浮市| 微山县| 朔州市| 曲靖市| 齐河县| 兰坪| 开阳县| 凉城县| 高陵县| 金寨县| 岚皋县| 镶黄旗| 西和县| 高尔夫| 太湖县| 清远市| 临高县| 黔东| 澜沧| 安国市|