久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 17322|回復: 1
打印 上一主題 下一主題
收起左側

uC/OS II 中就緒表的理解筆記(完整)

[復制鏈接]
跳轉到指定樓層
樓主
ID:71922 發表于 2015-1-10 22:29 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
================================== 2014.2.16 更新  ====================================
看著OS_EXT  INT8U        OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}  。
突然想到當初學AVR編程的時候,要給某一組引腳設置輸入輸出模式的時候,用的置位方法。
這個OSMapTbl 的存在原因,不就是為了把OSRdyTbl 的元素在OSRdyGrp 對應的位置位嗎?
想到一個改進的方法,其實應該可以去掉這個OSMapTbl 表。
原算法:
      優先級的表已經存在了優先級為31的任務,處在OSRdyTbl[]的第3元素,所以應把OSRdyGrp的第三位置1,
   
此時的OSRdyGrp 的值為 0b0000 1000 = 0x08    這個值剛好是OSMapTbl[3]的值。
      那么優先級為19的任務要加入就緒表,那么19優先級處在OSRdyTbl[] 的第2元素,所以應把OSRdyGrp的第二位置1 ,
      此時的OSRdyGrp 的值為 0b0000 0100 = 0x04  這個值也剛好是OSMapTbl[2]的值。

     兩個任務所在的優先級組都要在OSRdyGpr 留下狀態位,所以只要把兩個值進行或運算就能合并成 0b0000 1100 = 0x0C 。

我想到的改進方法那就是不查表,直接把0x01左移動 OSRdyTbl[]元素即可。
把原算法:
OSRdyGrp |= OSMapTbl[prio >> 3];
OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];
改成:
  OSRdyGrp |= 0x01<<(prio >> 3);
  OSRdyTbl[prio >> 3] |=  0x01<<(prio & 0x07 );

把上述例子代入算法:
首先是優先級31 默認就緒表中沒有任何任務就緒,所以OSRdyGrp為0
OSRdyGrp |= 0x01<<(31 >> 3)等于 0x00 |= 0x01<<0x03 等于 0x00 |= 0x08 最終OSRdyGrp=0x08 ;
現在看看優先級19
OSRdyGrp |= 0x01<<(19 >> 3)等于 0x08 |= 0x01<<0x02 等于 0x08 |= 0x04 最終OSRdyGrp=0x0C ;
這樣就不必要這個OSMapTbl表了,這個就可以節省RAM空間了。  
================================== 2014.2.15  ===================================
http://www.zg4o1577.cn/bbs/dpj-30372-1.html  參考鏈接
難得找到高清的視頻,看到就緒表算法的時候,思維晃進小胡同了。。。死活理解不過來。
為鞏固所得,先記下來。
UCOS-II 的優先級是值越小優先級越高 最高支持64級(0-63)0優先級最高,63優先級最低。

uC/OS II的就緒表結構設計的非常有意思,看看Labrosse(uC/OS II設計者)的就緒表結構設計。
任務就緒表是由一個OSRdyTbl數組表示,數組大小(OS_RDY_TBL_SIZE)由最低優先級(OS_LOWEST_PRIO)確定, 這樣可以減少不必要的空間浪費,節約RAM資源。
OSRdyTbl[]是INT8U 類型數組,每一個元素占8位。每一位表示一個優先級狀態(1為就緒,0則未就緒)。8個元素則可以表示64個優先級(8*8=64)。為加速就續表的查找,Labrosse把每個OSRdyTbl元素劃為每一優先級組,8個元素則有8個優先級組,它定義了一個INT8U類型的8位變量OSRdyGrp ,OSRdyGrp的每一位對應每個優先級組。如下圖:

假設優先級31的任務第一個加入了就緒任務表,此時OSRdyGrp和OSRdyTbl的情況:
OSRdyGrp的第3位為1,表示第3優先級組有就緒任務。
OSRdyTbl的第7位為1,表示第31優先級的任務被就緒。
此時OSRdyGrp的其他位為零,OSRdyTbl的其他元素中的位都為零

現在開始分析一下算法。
定義:
#define  OS_RDY_TBL_SIZE   ((OS_LOWEST_PRIO) / 8 + 1)
OS_EXT  INT8U     OSRdyGrp;                           
OS_EXT  INT8U     OSRdyTbl[OS_RDY_TBL_SIZE];
OS_EXT  INT8U        OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}
先說說把指定優先級任務加入就緒表的算法。
OSRdyGrp |= OSMapTbl[prio >> 3];                              // prio 表示指定的優先級  
OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];
上面解釋了那么多,就是為了這倆句。
先看看 prio>>3 為什么要右移三位。
UCOS-II最多支持64個優先級,即從0到63。最低的優先級為63 轉換成二進制:0x00111111
剛好占6位,那么可以把6為劃分為高三位和低三位,就拿上面的優先級為31任務的例子來說:
31取其高三位 31>>3 = 3 ,看,是不是剛好表示OSRdyGrp的第3位?也就是說在OSRdyTbl[3]。
31取其低三位 31&0x07 = 7,看,是不是剛好表示OSRdyTbl的第7位?也就是說在OSRdyTbl[3]的第7位。
兩個組合起來:31的優先級在OSRdyTbl的第3個元素中的第7位。
這就是為什么prio >> 3 和 prio & 0x07了 。

(視頻教程可坑死我了,說是在OSRdyGrp分6位。郁悶。。。我就在想,OSRdyGrp的每一位不是都對應這就緒表的每一組嗎?怎么就又分6位了,現在搞明白這點,一下子全通了。。。)
得到之后如何進一步得到OSRdyGrp的值和OSRdyTbl中第3個元素的值呢?
從上圖來看,OSRdyGrp的第三位置1 所以OSRdyGrp = 0b0000 1000 = 0x08  而OSRdyTbl[3]的第七位被置1 所以等于 OSRdyTbl[3] = 0b1000 0000 = 0x80 。
那么我們繼續分析它的算法,剩下的算法很簡單啦,就是將得到的值和OSMapTbl表對應起來。典型的用空間換時間的方法。
OSRdyGrp[31>>3] = 0x08,OSRdyGrp[31&0x07] = 0x80
剛好和我們上圖看的結果一樣。那既然得到了 OSRdyGrp的值和OSRdyTbl[3]那為什么不直接復制過去呢,而是要與其相| (或),這是因為OSRdyGrp的每一位記錄著每一個優先級組是否有任務就緒的狀態,而OSRdyTbl的每一位都記錄著每個優先級的就緒狀態。如果直接賦值,則會覆蓋所有的狀態位,所以要用 或運算 來合并,這樣就不會影響其他位的狀態了。

舉個例子:
例如 優先級19的任務此時要進入就緒任務表
就緒表中已經有優先級為31的任務
那么
此時的OSRdyGrp 的值為 0b00001000 = 0x08
此時的OSRdyTbl[3]的值為 0b10000000 = 0x80
現在要將優先級為19的任務加入就緒表中
根據算法:
OSRdyGrp |= OSMapTbl[prio >> 3];
OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];
一步一步來
// OSRdyGrp |= OSMapTbl[prio >> 3];
19 >> 3 = 0x02;       // 取高三位,確定在第2優先級組 即 OSRdyTbl[2]
OSMapTbl[0x02] = 0x04;       // 查表得到 OSRdyGrp 的值應為 0x04 = 0b0000 0100
0x08(OSRdyGrp)| 0x04 = 0x0C; // 0b0000 1000 | 0b0000 0100 = 0b0000 1100 和原OSRdyGrp合并得到新的值 0x0C

// OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];
19 & 0x07 = 0x03       // 取低三位,確定在OSRdyTbl[2]的第三位
OSMapTbl[0x03] = 0x08; // 查表得到OSRdyTbl[2]的值為0x08
0x00(OSRdyTbl[0x02]) | 0x08 = 0x08; // 0b0000 0000 | 0b 0000 1000 = 0x08和原OSRdyTbl[0x02]合并得到新的值 0x08
那么此時的就緒表和OSRdyGrp 的每一位狀態應為:
      
OSRdyGrp
   
      
0
   
      
0
   
      
0
   
      
0
   
      
1
   
      
1
   
      
0
   
      
0
而OSRdyTbl的每一位狀態應為
      
OSRdyTbl[0]
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
OSRdyTbl[1]
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
OSRdyTbl[2]
   
      
0
   
      
0
   
      
0
   
      
0
   
      
1
   
      
0
   
      
0
   
      
0
   
      
OSRdyTbl[3]
   
      
1
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
OSRdyTbl[4]
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
OSRdyTbl[5]
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
OSRdyTbl[6]
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
OSRdyTbl[7]
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
      
0
   
先寫到這,現在只是明白了算法的原理,還不太理解OSRdyGrp存在的意義。

================================== 2014.2.16 更新  =======================
看著OS_EXT  INT8U        OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}  。
突然想到當初學AVR編程的時候,要給某一組引腳設置輸入輸出模式的時候,用的置位方法。
這個OSMapTbl 的存在原因,不就是為了把OSRdyTbl 的元素在OSRdyGrp 對應的位置位嗎?
想到一個改進的方法,其實應該可以去掉這個OSMapTbl 表。
原算法:
      優先級的表已經存在了優先級為31的任務,處在OSRdyTbl[]的第3元素,所以應把OSRdyGrp的第三位置1,
    此時的OSRdyGrp 的值為 0b0000 1000 = 0x08    這個值剛好是OSMapTbl[3]的值。
      那么優先級為19的任務要加入就緒表,那么19優先級處在OSRdyTbl[] 的第2元素,所以應把OSRdyGrp的第二位置1 ,
      此時的OSRdyGrp 的值為 0b0000 0100 = 0x04  這個值也剛好是OSMapTbl[2]的值。

     兩個任務所在的優先級組都要在OSRdyGpr 留下狀態位,所以只要把兩個值進行或運算就能合并成 0b0000 1100 = 0x0C 。

我想到的改進方法那就是不查表,直接把0x01左移動 OSRdyTbl[]元素即可。
把原算法:
OSRdyGrp |= OSMapTbl[prio >> 3];
OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];
改成:
  OSRdyGrp |= 0x01<<(prio >> 3);
  OSRdyTbl[prio >> 3] |=  0x01<<(prio & 0x07 );

把上述例子代入算法:
首先是優先級31 默認就緒表中沒有任何任務就緒,所以OSRdyGrp為0
OSRdyGrp |= 0x01<<(31 >> 3)等于 0x00 |= 0x01<<0x03 等于 0x00 |= 0x08 最終OSRdyGrp=0x08 ;
現在看看優先級19
OSRdyGrp |= 0x01<<(19 >> 3)等于 0x08 |= 0x01<<0x02 等于 0x08 |= 0x04 最終OSRdyGrp=0x0C ;
這樣就不必要這個OSMapTbl表了,這個就可以節省RAM空間了。  
================================== 2014.2.18 更新  ===================

上面說的是添加任務到就緒表,接下來說說把指定任務從就緒表中刪除。
下面就是uCOS-II的實現代碼:
if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0)   
     OSRdyGrp &= ~OSMapTbl[prio >> 3];

復習一下。
優先級值右移動三位(prio >> 3),就能得到該優先級在OSRdyTbl[]數組中的第幾組。
而取優先級值的后三位(
prio & 0x07),就能得到該優先級在OSRdyTbl[]數組中某一組的第幾位。
OSRdyGrp 中的每一位都代表著OSMapTbl 的每一個元素,例如 OSRdyGrp的第2位被置1,則說明OSMapTbl[2]至少有一位被置1。
要在就緒表刪除指定優先級任務,首先
1、在OSRdyTbl數組中把該優先級所在的位清0(把1改為0),
2、然后判斷其所在的優先級組是否為0,為0則說明該優先級組中的優先級全都沒有被設置就緒。此時就可以把該優先級組與OSRdyGrp           相對應的位清0。否則不需要更改OSrdyGrp。

按照上面的例子,就緒表中只有優先級為31和19的任務就緒。那么OSRdyGrp和OSRdyTbl數組的值如下:
OSRdyGrp = 0x0C ;
OSRdyTbl[0] = 0x00;
OSRdyTbl[1] = 0x00;
OSRdyTbl[2] = 0x08;
OSRdyTbl[3] = 0x80;
OSRdyTbl[4] = 0x00;
...
OSRdyTbl[7] = 0x00;   

我把OSMapTbl表寫出來的,計算的時候方便看:OS_EXT  INT8U    OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}  
現在我們要把優先級為19的任務從就緒表中刪除。步驟應如下:
1、
19 & 0x07 = 3   // 得到19優先級在OSRdyTbl[]數組中某一組的第3位 (此位會為1)
OSMapTbl[3]  = 0x08  // 查表得知 1字節中的第三位為1時值為0x08,OSMapTbl表主要是用來求1字節中某一位為1時,值是多少。
~0x08 = 0xF7   // 0x08 = 0b0000 1000 取反得 0b1111 0111,這步是為了給該位清零準備的。
2、
  19 >> 3= 0x02   // 得到19優先級所在的優先級組,即該優先級在OSRdyTbl[2]
   OSRdyTbl[ 0x02 ] = 0x08  // 將整組值取出 這一步也是為該優先級清0做準備
3、
  OSRdyTbl[ 0x02 ]  & 0xF7 // 將優先級組與指定優先級取反的值進行與運算達到將指定優先級所在的位清0又不影響其他狀態位的目的。
                                               0x08 = 0b00001000 & 0b11110111 = 0x00 最終OSRdyTbl[2]=0x00      
4、
     if(OSRdyTbl[2]  == 0 )    // 如果為0則需要將該優先級組與OSRdyGrp對應的狀態位清0。方法如下:
      OSRdyGrp & 0xF7// 將OSRdyGrp與指定優先級取反的值進行與運算達到將指定優先級組所在的位清0而又不影響其他狀態位的目的。               

把上面代碼簡化就得到uCOSii的算法代碼了:
if ((OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07]) == 0)       // 將OSRdyTbl[]的指定狀態位清0并判斷所在的優先級組是否為0
     OSRdyGrp &= ~OSMapTbl[prio >> 3];                 // 為0則將該優先級組與OSRdyGrp對應的狀態位清0

至此,在就緒表中刪除指定優先級的任務的實現原理和方法已經完畢。
在就緒表中查找已經就緒的最高優先級任務的實現方法和原理只能晚上再來分析了,那個是重點中的重點啊,直接影響uCOS-ii系統內核的效率。
  
      
================================== 2014.3.22  ===================================
就緒表中查找已經就緒的最高優先級任務的實現方法和原理.
實時操作相同的任務切換速度很快,每次做任務切換時,UCOS 都要找到優先級最高的任務來執行,所以從就緒表中尋找最高優先級的任務的效率直接就影響了UCOS內核的效率。

首先我們看看UCOS的算法:
INT8U const OSUnMapTbl[256] = {
    0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};
y = OSUnMapTal[ OSRdyGrp ];                     // 取最高優先級所在的任務組
x = OSUnMapTal[OSRdyTbl[y]]                     // 取該任務組中最高的優先級
prio = (y << 3) + x;                                   // 組合計算
很簡單,就三句代碼。剛開始我看到這個很詫異,為什么要浪費256個字節的空間來存放這些很奇怪的數值。用個循環不就可以確定優先級了嗎?原來,在實時操作系統的任何操作都必須可預知的,而循環則無法確定其執行的時間。
我們看看OSUnMapTbl[256]數組是如何出來的。
由于處于就緒狀態的任務可能有多個,也就是說OSRdyGrp和 OSRdyTbl[]中有可能不止一位是被置1的。由于優先級的數字越小,優先級就越高,所以要從這些就緒的任務中找出優先級最高的任務,只需要取OSRdyGrp和OSRdyTbl[]中被置1的最低位。
過程: 取OSRdyGrp中被置1的最低位y,得到最高優先級所在的任務組(即在OSRdyTbl[]的y元素),再取這個任務組中被置1的最低位x,得到最高優先級在OSRdyTbl[]所對于的位,再通過y與x的組合就得到了最高優先級。

那么要解決的問題出現了,怎么去找OSRdyGrp、OSRdyTbl[]被置1的最低位呢?哈,就是上面那個很詭異的OSUnMapTbl[]表啦,不能用循環就只能查表方法了。OSRdyGrp和OSRdyTbl[]元素都占用一個字節,一個字節等于8位,2^8 = 256 種可能性,所以定義了256個字節的OSUnMapTbl[]表。
下面是依次把各種可能性寫下來。
0x00 ==00000000b 最低位為1的位數為 bit0==0==OSUnMapTbl[0](其實為空,空的情況默認為0,不影響計算)
0x01 ==00000001b 最低位為1的位數為 bit0==0==OSUnMapTbl[1]
0x02 ==00000010b 最低位為1的位數為 bit1==1==OSUnMapTbl[2]
0x03 ==00000011b 最低位為1的位數為bit0==0==OSUnMapTbl[3] (有兩個為1的位,bit0,bit1,取最小的,因為OSRdyGrp或OSOSRdyTbl中最小的位數 對應的優先級越大)
0x04 ==00000100b 最低位為1的位數為 bit2==2==OSUnMapTbl[4]
0x05 ==00000101b 最低位為1的位數為 bit0==0==OSUnMapTbl[5]
0x06 ==00000110b 最低位為1的位數為 bit1==1==OSUnMapTbl[6]
0x07 ==00000111b 最低位為1的位數為 bit0==0==OSUnMapTbl[7]
0x08 ==00001000b 最低位為1的位數為 bit3==3==OSUnMapTbl[8]
0x09 ==00001001b 最低位為1的位數為 bit0==0==OSUnMapTbl[9]
0x0A ==00001010b 最低位為1的位數為 bit1==1==OSUnMapTbl[10]
0x0B ==00001011b 最低位為1的位數為 bit0==0==OSUnMapTbl[11]
0x0C ==00001100b 最低位為1的位數為 bit2==2==OSUnMapTbl[12]
0x0D ==00001101b 最低位為1的位數為 bit0==0==OSUnMapTbl[13]
0x0E ==00001110b 最低位為1的位數為 bit1==1==OSUnMapTbl[14]
0x0F ==00001111b 最低位為1的位數為 bit0==0==OSUnMapTbl[15]
y = OSUnMapTal[ OSRdyGrp ];  
// 通過查表取得OSRdyGrp最低有效位(被置1的位),即取得最高優先級所在的任務組。
x = OSUnMapTal[OSRdyTbl[y]];
// 通過查表取得該任務組中最低有效位,即取得最高優先級所對應的OSRdyTbl[y]位。
prio = (y << 3) + x;                                   
// 根據OSRdyGrp與OSRdyTbl[]、OSRdyTbl[]與優先級的對應關系,計算出OSRdyTbl[y]中的x位與OSRdyTbl[0]中的第0位的位數。
如在OSRdyTbl[3]中的第6位,3*8 = 24,OSRdyTbl[3]前面有24位,再加上OSRdyTbl[3]中的6位,等于30 。




分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏3 分享淘帖 頂1 踩
回復

使用道具 舉報

沙發
ID:188815 發表于 2017-4-12 15:27 | 只看該作者
很詳細,大贊!
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日韩视频精品在线 | 成人午夜免费在线视频 | 在线播放一区二区三区 | 日韩网 | 精品国产一区二区三区久久久蜜月 | 日本黄色高清视频 | 免费性视频 | 久久久精品网 | 亚洲欧美视频 | 日日干日日色 | 九九伊人sl水蜜桃色推荐 | 二区在线观看 | 精品二区视频 | 狠狠久久 | 欧美日韩久久精品 | 国产片侵犯亲女视频播放 | 亚洲伊人精品酒店 | 亚洲国产在 | 国产视频h | 91精品国产一区二区三区 | 国产在线一区二区三区 | 91嫩草精品 | 啪啪免费 | 九九热精品视频 | 欧美淫片 | 日本成人久久 | 日日夜夜免费精品视频 | 97天天干| 亚洲成人动漫在线观看 | 一级毛片视频在线观看 | 色视频网站 | 欧美另类视频 | 欧美精品一区二区三区四区 在线 | 午夜精品一区二区三区在线观看 | 中文字幕免费在线 | 永久看片 | 91亚洲国产成人久久精品网站 | 综合二区 | 婷婷成人在线 | 亚洲精品久久久久久久久久久 | 精品免费视频一区二区 |