ii任務就緒表" rel="noopener noreferrer">uc/os ii任務就緒表
simplorer
先來了解一下uc/os ii的任務狀態。uc/os ii的任務共分為五種狀態:dormant(休眠)、waiting(等待)、running(執行)、ready(就緒)以及isp(中斷)。
dormant:指該任務駐留記憶體,但是不被任務排程器排程,被刪除的任務就處於這種狀態;
waiting:指該任務在某一事件的發生,例如等待某外設的i/o操作,等待某共享資源由暫不能使用變成能使用狀態,等待定時脈衝的到來或等待超時訊號的到來以結束目前的等待,等等;
running:指該任務掌握了cpu的使用權,正在執行中;
ready :指該任務已經準備好,可以執行了,但是由於優先順序低於別的任務,暫時不能執行,只能在就緒表中等待;
isp
:指發生中斷時,cpu需要相應中斷,正在執行中的任務被打斷,就進入了isp狀態。
圖1. 是uc/os ii系統的任務狀態切換圖,具體的切換過程在本文中不做深究。
圖1. uc/os ii任務狀態切換圖
對於2.52版本的uc/os ii來說,共有64級的任務優先順序,編號為0~63,數字越小,優先順序越低。必須保證所有任務都分配到不同的優先順序。系統保留了4個最高優先順序的任務和4個最低優先順序的任務,所有使用者可以使用的任務數有56個。當μc/os-ⅱ初始化的時候,最低優先順序os_lowest_pr1o總是被賦給空閒任務idle task。
如果同時只有乙個任務處於就緒狀態,os直接執行就可以了,但是如果同時多個任務都處於就緒狀態,os怎麼操作?這就引出了就緒表的問題。uc/os ii的就緒表結構設計的十分巧妙,現在你也許感受不到,等我介紹完了就緒表的整個結構,及其帶來的便利,大家就會佩服labrosse的天才思維了。
考慮到系統只有64級的任務優先順序,labrosse設計了兩個變數osrdygrp和osrdytbl。把就緒表分成8*8的乙個矩陣形表(使用全部優先順序的情況)。變數宣告如下:
os_ext int8u
osrdygrp;
os_ext int8u
osrdytbl[os_rdy_tbl_size];
從宣告中可以看出,osrdygrp為乙個8位的無符號字元型,而osrdytbl則是乙個8位的無符號字元陣列,字元陣列的大小由下面的**給出:
#define os_rdy_tbl_size
((os_lowest_prio) / 8 + 1)
可以說,字元陣列的大小是根據你所定義的任務個數改變的,這樣可以減少不必要的空間浪費,節約ram資源。
圖2. uc/os ii就緒表
osrdygrp代表任務優先順序的組,一位代表乙個優先順序組,當某位被置1時,表示該組中至少有乙個任務優先順序被設定了。比如osrdygrp = 0x01,則代表第一組(優先順序為8~15)中的某乙個或多個優先順序有效。通過檢查osrdygrp的值可以確定某一組是否有優先順序有效,但是無法確定到底有幾個優先順序有效。這時,就需要陣列osrdytbl確定具體的優先順序位置了。
假設優先順序為31的任務進入就緒表(只有這乙個任務),如何確定osrdygrp與osrdytbl的值呢?先通過圖例法觀察,如圖3所示:
圖3. 圖形法求解變數
從圖3中,可以方便的得出osrdygrp = 0x08,osrdytbl[3] = 0x80,這種方式反映到**上,可以是如下形式:
osrdygrp = 2^(prio / 8);
osrdytbl[prio / 8] = 2^(prio % 8);
當然,上面的**只是簡單的實現了所需的功能,沒有什麼效率可言,對於一般的處理器來說,位操作都要比算術操作速度要快,於是使用位操作代替上面**中的算術操作 。
osrdygrp = (1 << (prio >> 3));
osrdytbl[prio >> 3] = (1 << (prio & 0x07));
好了,我現在已經開始沾沾自喜了,因為我成功了優化了部分**,提高了os的效率。對於大師來說,這些優化還不是最優的,上面的**還有繼續「壓榨」的可能性。位操作雖然比算術運算效率高,還有一種效率更高的做法-----查表。第一次運算,再次使用,不通過運算,直接通過查表,得到結果。
對於只有64級優先順序的系統來說,prio的取值最大為63,則prio >> 3與prio & 0x70表示式的值位於0~7位之間。而對於1 << (prio >> 3)和
1 << (prio & 0x70))來說,由於右移了移位,表示式的值在1~8位之間。
令變數ostcbx = prio & 0x07,ostcby = prio >> 3,ostcbbitx = 1 << (prio & 0x07),ostcbbity = 1 << (prio >> 3),同時設計乙個陣列osmaptbl = ,則可以實現如下的對應關係:
ostcbbitx = osmaptbl[ostcbx];
ostcbbity = osmaptbl[ostcby];
我們最初求解的等式可以表達為;
osrdygrp = osmaptbl[ostcby];
osrdytbl[prio >> 3] = osmaptbl[ostcbx];
增加、刪除某一任務,為了不影響整個就緒表,實際操作中使用的是或運算,這點請注意。
osrdygrp = osmaptbl[prio >> 3];
osrdytbl[prio >> 3] = osmaptbl[prio & 0x07];
if ((osrdytbl[prio >> 3] &= ~osmaptbl[prio & 0x07]) == 0)
osrdygrp &= ~osmaptbl[prio >> 3]
現在,任務優先順序如何加入,退出就緒表已經明白了,那麼另乙個問題來了,如何找出進入就緒態的優先順序最高的任務?我可以想到的辦法就是掃瞄整個**,或者說遍歷整個**,優先順序越高,掃瞄的時間越短,如果剛好是63號優先順序,則所花費時間最長,當然還可以採用一些常用的演算法減少平均掃瞄時間,最終都無法保證掃瞄時間是個常數。
通過觀察上面等式的求解過程,還可以得出乙個結論:prio值的高3位決定優先順序屬於哪個組,而低3位決定優先順序處於這一組的具體位置。labrosse先生於是又設計乙個名為osunmaptbl的查詢表,利用空間換時間的方式,將查詢任務的時間固定為乙個值。為理解這個**的工作原理,我們假設osrdygrp = 0b10101010,即第1,3,5,7組為1,對應的osrdytbl[1] = 0b10101010,osrdytbl[3] = 0b10101010,osrdytbl[5] = 0b10101010,osrdytbl[7] = 0b10101010
又y = osunmaptbl[osrdygrp] = osunmaptbl[170] = 1,x= osunmaptbl[osrdytbl[y]] = osunmaptbl[170] = 1,最終**中的最高優先順序prio =y<<3 + x=9。也就是說現有就緒表中優先順序最高的任務是9號任務,這與假設相同。
ucos II 任務就緒表學習筆記
就緒表中有兩個變數 osrdygrp和 osrdytbl.這兩個變數的對應關係是 osrdytbl n 中任何一位是1時,osrdygrp 的第n 位 是1。相當於osrdygrp 是osrdytbl的索引。具體的對應關係如下圖 陣列osrdytbl 8 按位來算的話正好是64個位 64個優先順序。...
uC OS II就緒任務的管理
uc os ii就緒任務的管理 uc os ii總是在已就緒的任務中選擇乙個任務來執行。為了了解系統中的任務哪些是就緒任務,uc os ii在系統初始化時間裡了乙個供就緒任務登記的表,整個表就叫做就緒任務表。uc os ii的就緒任務表實質上是乙個型別為int8u的陣列osrdytbl 其中的每一位...
uC OS II就緒任務的管理
uc os ii就緒任務的管理 uc os ii總是在已就緒的任務中選擇乙個任務來執行。為了了解系統中的任務哪些是就緒任務,uc os ii在系統初始化時間裡了乙個供就緒任務登記的表,整個表就叫做就緒任務表。uc os ii的就緒任務表實質上是乙個型別為int8u的陣列osrdytbl 其中的每一位...