1. 程式人生 > >UCOS II怎麼查詢當前就緒表中,優先順序最高的任務

UCOS II怎麼查詢當前就緒表中,優先順序最高的任務

uCOS-II為了保證CPU總是執行優先順序最高的任務,每當任務狀態發生變化時,就需要判斷當前任務是否為最高優先順序,不是的話就需要進行上下文切換。如何在需要進行任務優先順序比較時,快速的將就緒態任務中優先順序最高的讀出。一種最簡單的資料結構就是定義一個unsigned int型別的變數。變數長度為4位元組共32位,如果用1代表任務就緒,用0代表任務未就緒,用相應的位來代表任務優先順序,那麼這樣總共能定義32個任務。


如上圖所示,第一行代表該位的取值,第二行代表位,那麼總共定義了32個任務,優先順序分別為0-31,其中優先順序為0,、29、31的任務處於就緒狀態。這個說白了就是定義了一個長度為32的bool型陣列,下標代表任務的優先順序,該下標對應的值便為任務的狀態。如果要讀出就緒表中處於就緒狀態並且優先順序最高的任務,那麼執行這條語句:

for(i=0;i<32&&(!(num&(0x01<<i)));i++);
其中num為定義的unsigned int 型別的變數,執行完這條語句之後,i的值就是就緒任務中優先順序最高的任務所對應的優先順序。

這樣做確實簡單明瞭,但是定義的任務偏少,而且讀出一個特定任務優先順序所需要的時間是不定的,就是說上面讀出優先順序的那條語句的執行次數是不定的,這顯然不能滿足實時性系統的要求。

所以就有了uCOS-II的神來之筆,unsigned int型別的變數可以看做是長度為32的bool型陣列,如果將這個陣列從一維定義到二維,那麼定義的任務數量將翻倍增長。如果這個二維陣列的列數為8,那麼8位二進位制數剛好可以用unsigned char來表示,那麼定義一個一維的unsigned char陣列就可以表示這種二維的bool型陣列,uCOS-II總共可以管理64個任務,那麼unsigned char陣列的長度為8,便可以定義出64個任務,剛好滿足要求。定義完之後的資料結構如下。



假設這個陣列為data[],那麼在上圖中,data[0]=0xA6,data[6]=0X37,在第一行中,優先順序為1、2、5、7的任務處於就緒狀態,如何快速的讀出處於就緒狀態且優先順序最高的任務,最笨的辦法就是遍歷這個陣列,依次取出陣列中的每個元素,每取出一個元素,讀這個元素各個位的值,從低到高,直到找出第一個位為1的那一位。用元素的下標乘8再加上該位的值,就是優先順序最高的任務。這種做法顯然效率很低,而且執行這個演算法的所需要的時間不定。

這個演算法效率低下的原因就是把時間浪費在了讀取那些未就緒任務的狀態,假設就緒態任務中優先順序最高為103,那麼依次讀取前102個任務的狀態值浪費了大量的時間,如果能想辦法跳過一些前面未就緒的任務,那麼演算法的效率就大大提升。如果將所有的任務分組,每八個為一組,總共八組,定義一個unsigned char型別的變數,假設為grp,用這個變數的每一位代表一個任務組。只要這個任務組中八個任務其中有一個處於就緒態,那麼就將這個變數相應的位置1,如果所有的任務都未就緒,那麼就將這個變數相應的位置0。這樣就達到了前面所說跳過一些未就緒任務的想法,在遍歷陣列查詢優先順序時,從低到高首先去讀grp每一位的值,如果發現某一位值為0,就代表這個組沒有就緒態的任務,就跳過這個組。這樣遍歷data陣列時,步長從1變為了8。

解決了前面的問題後,這個演算法效率還是有些低,原因在於遍歷。假設grp的值為0XA0(1010 0000),遍歷的結果是優先順序最高的就緒態任務在第五組,

for(i=0;i<32&&(!(num&(0x01<<i)));i++);

上面這句程式碼執行了五次,時間浪費在這裡了。如果將程式碼執行的次數降低到最小,並且是確定的,那麼效率將會進一步提升。如果定義一個長度為256的unsigned char陣列(假設為indexOf1),將grp的值作為下標,該下標處元素的值為該下標值從低到高第一次出現1的位的位置。舉例來說,0XA0(1010 0000)從低到高第一次出現1的位的位置為5,那麼indexOf1[grp]=5。同理indexOf1[0]=0,indexOf1[1]=0,indexOf1[2]=1,… 於是在uCOS-II原始碼中定義了這樣一個數組



這樣就不用執行前面所述的那句程式碼,直接通過下標在陣列中查詢即可,程式碼執行的次數降到了最低而且次數是確定的。

那麼總結一下查詢最高優先順序的演算法,首先將grp作為下標,在indexOf1陣列中查詢grp第一次出現1的位的位置(假設為y),旨在跳過前面未就緒的任務組。以y為下標,取出就緒表data[]陣列中對應元素,繼續以該元素為下標,在indexO1陣列中查詢該元素第一次出現1的位的位置(假設為x),旨在跳過同組中前面未就緒的任務。這樣總共跳過的未就緒的任務個數為 y組+x 個。每組的任務為8,那麼跳過的任務數就是y*8+3,那麼就緒任務中優先順序最高的就是該值。以下面的這張就緒表為例:



grp的值為0XE0(1110 0000),表示0-4組沒有就緒的任務,5-7有就緒的任務。首先以grp為下標,indexOf1[grp]=5,取出就緒表中data[5],值為0X98(1001 1000),以0X98為下標,在indexOf1中取出indexOf1[0X98]=3,那麼總共跳過了5組+3個共43個任務,那麼就緒任務中優先順序最高的就是43。

在uCOS-II原始碼中,grp定義為OSRdyGrp,就緒表data[]定義為OSRdyTbl[OS_LOWST_PRIO/8+1],indexOf1[256]定義為OSUnMapTbl[256],

查詢程式碼為:

y      = OSUnMapTbl[OSRdyGrp];  
x = OSUnMapTbl[OSRdyTbl[y]];
prio = (y << 3) + x;

相關推薦

UCOS II怎麼查詢當前就緒優先順序最高任務

uCOS-II為了保證CPU總是執行優先順序最高的任務,每當任務狀態發生變化時,就需要判斷當前任務是否為最高優先順序,不是的話就需要進行上下文切換。如何在需要進行任務優先順序比較時,快速的將就緒態任務中優先順序最高的讀出。一種最簡單的資料結構就是定義一個unsi

查詢幾個資料根據存在情況插入到另一個

INSERT INTO now_pay_cust_stat (     customer_id,     n_p_custid,     sum_offer_order,     sum_offer_p

查詢的資料插入到另一張分為兩種情況一種是目標不存在另一種是目標存在。

         情況一(目標表不存在,建立表名為t1的表,將person表中全部資料插入): createtablet1 asselect* fromperson;情況二(目標表t1存在,將per

SQL一個使用者具有多個角色查詢出該具有該使用者的所有角色的其他使用者

  select count(*) as num,tb.id                   from                   tb,                   (select role from tb where id=xxx) as t1

查詢A、BAB沒有的資料

(轉)A、B兩表,找出ID欄位中,存在A表,但是不存在B表的資料。A表總共13w資料,去重後大約3W條資料,B表有2W條資料,且B表的ID欄位有索引。 方法一   使用 not in ,容易理解,效率低  ~執行時間為:1.395秒~ 1 select distin

SQL Server Orcale 如何查詢資料庫或者的索引

SQL Server資料庫索引資訊查詢 -- 檢視某個表的索引 SELECT * FROM sys.sysindexes WHERE id=object_id('RelactionGraph')

查詢當前執行的SQL與解鎖

一:查詢當前正在執行的SQL:SELECT a.sid, a.serial#, a.machine, a.username, b.hash_value, c.sql_text  FROM v$session a, v$sqlarea b, v$sqltext c WHERE

mysql 查詢 兩個不同字段的 和並通過兩個的時間來分組

mysql data new 字段 class 兩張 time sele group ( SELECT sum( a.cost_sum ) AS sum_cost, sum( a.phone_sum ) AS sum_phone, s

使用一條sql查詢多個的記錄數

nbsp lec sel code spa select bold style 查詢 方法一: select t1.num1,t2.num2,t3.num3 from (select count(*) num1 from table1) t1, (se

插入一個元素到有序順序使其再次有序

程式碼: #include <stdio.h> /* 題目:資料結構題集17頁2.11 設順序表中資料元素遞增有序,試寫一演算法,將x插入到順序表的適當位置上,以保持該表的有序性 演算法:逆序遍歷順序表找合適的插入new_elem的位置,並將其插入 */ #define maxl

mysql如何查詢某個資料時間最新的多條資料

通過t_test表的time欄位來比較。 SELECT a.* FROM t_test a WHERE NOT EXISTS(SELECT 1 FROM t_test b WHERE b.tim

sql 怎麼將A插入B去除兩張 含有的重複資料

insert into B(欄位列表) select 欄位列表 from A  where not exists(select * from B where a.keycol1 = b.keycol1) keycol1為A表和B 表中的欄位,可能帶有主鍵,可以此欄位來判斷A表和B表中是

查詢某張時間最近的一條資料

SELECT   a1.id          FROM a a1          LEFT JOIN b b1 ON a1.cid = b1.cid

資料庫SQL實戰——對於employees給出奇數行的first_name

題目的敘述有問題,正確敘述:對於employees表,在對first_name進行排名後,選出奇數排名對應的first_name。 題目描述 對於employees表中,給出奇數行的first_name CREATE TABLE `employees` ( `emp_no` int(11

Java基於SSM,省市區三級聯動後臺查詢(單附(建表語句+查詢Sql)

1、建表語句 CREATE TABLE "hxdb"."sys_area" ( "id" varchar(64) COLLATE "default" NOT NULL, "code" varchar(

資料庫讀取原始資料插入新對處理原始資料的原則總結

在讀取原始資料的時候會有可能屬性名的名字與要建立的表的名字不符,這個時候就要為讀取到的資料重新命名屬性名。 如果資料中存在中文,還要宣告資料庫的編碼。 在原始表中可能會有重複資料,需要事先將重複資料進行刪除,然後再做其他處理。 在設定主鍵的時候會發現有些資料的主鍵相同,但是其他屬性值不同,需要對已經插入

mysql 獲取一張 另一張不存在的資料

   編寫sql語句中,經常需要編寫獲取一張資料表中不存在與另一張表的資料,相關編寫方法如下:  方法1: 使用not in ,效率低下,在資料較小的情況下可以採用如下編寫    SELECT * FROM a WHERE 1=1 AND a.Id NOT IN( SELECT

資料庫SQL實踐61:對於employees給出奇數行的first_name

思路: 將小於等於e1.first_name的first_name的個數統計下,然後求餘2看是否等於1,若是則取出。 select e1.first_name from employees e1 where(select count(*) from employees e2 where e1

mysql查詢的結果在新增一列作為排序使用 @row_num

// 在結果表後在加一列遞增一 作為排名使用 // 為了分頁的時候排名是在整體資料上進行排序而不是每一頁都是從1開始這個 @row_num應該是動態的 #{offset} 和limt #{offset} 一致 SET @row_num = 11; // 由於查詢的條件