電電俠 ? 坐公交車、辦理業(yè)務(wù)等經(jīng)常需要排隊(duì),計(jì)算機(jī)系統(tǒng)中也有類似的“隊(duì)列“概念嗎? ?
當(dāng)然。隊(duì)列被用作進(jìn)程之間的通信管道,通常是一對一的,如下圖所示。
科科君
任務(wù) A 將信息存入隊(duì)列,任務(wù)B以先進(jìn)先出的方式提取信息。隊(duì)列通常應(yīng)足夠大,可以承載許多數(shù)據(jù),而不僅僅承載單個(gè)數(shù)據(jù)項(xiàng)。因此,它可以充當(dāng)緩沖或暫存器,為管道提供靈活性。它的優(yōu)點(diǎn)是插入和提取功能可以異步進(jìn)行(只要管道沒有填滿)。它在 RAM 中實(shí)現(xiàn)。進(jìn)程之間傳遞的信息可能是數(shù)據(jù)本身,也可能是指向數(shù)據(jù)的指針。指針通常用于在 RAM 存儲受限時(shí)處理大量數(shù)據(jù)。實(shí)現(xiàn)隊(duì)列的技術(shù)有兩種:鏈表類型結(jié)構(gòu)和循環(huán)緩沖區(qū)。
電電俠 ? 想了解下鏈表的特性。 ? 鏈表的一個(gè)非常有用的特性是它的大小不一定是固定的,而是可以根據(jù)需要擴(kuò)大或縮小。 科科君
此外,可以構(gòu)建非常大的隊(duì)列,僅受可用內(nèi)存空間的限制。但是對于嵌入式系統(tǒng)來說,這些并不是特別的優(yōu)勢。首先,如果 RAM 有限,則根本不可能構(gòu)造很大的隊(duì)列。其次,處理多個(gè)消息的大型FIFO隊(duì)列從數(shù)據(jù)輸入到數(shù)據(jù)輸出可能會有較長的傳輸延遲,就性能而言,對于許多實(shí)時(shí)應(yīng)用可能太慢。因此,用于嵌入式的首選隊(duì)列(通道)結(jié)構(gòu)是循環(huán)緩沖區(qū),如下圖所示。
電電俠 ? 循環(huán)緩存區(qū)應(yīng)該如何設(shè)計(jì)? ?
循環(huán)緩沖區(qū)通常設(shè)計(jì)為使用固定數(shù)量的內(nèi)存空間,用來保存一定數(shù)量的數(shù)據(jù),如上圖(a) 所示。
科科君
緩沖區(qū)大小是在創(chuàng)建時(shí)定義的(例如這里是10個(gè)數(shù)據(jù)單位),但在之后是固定的。使其循環(huán)的原因是數(shù)據(jù)單元0是數(shù)據(jù)單元9的后繼,尋址是使用模9計(jì)數(shù)器完成的(就像12小時(shí)時(shí)鐘使用模12計(jì)算一樣)。
電電俠 ? 在讀寫操作期間,數(shù)據(jù)如果在通道中移動(dòng),時(shí)間開銷增加怎么辦? ?
但是,一般來說這會帶來不可接受的時(shí)間開銷。
科科君
這里使用另一種方法,上圖(b)展示了如何使用指針來標(biāo)識存儲數(shù)據(jù)的起始和結(jié)束位置(“讀取者”和“發(fā)送者”)。通過指針,不必在緩沖區(qū)中移動(dòng)數(shù)據(jù)。插入的數(shù)據(jù)單元始終位于相同的內(nèi)存位置,僅需改變指針的值,圖(c)和圖(d)所示。這些指針也可以用來定義隊(duì)列滿和隊(duì)列空的條件(當(dāng)它們相等時(shí))。
電電俠 ? 什么情況下任務(wù)會掛起? ?
在正常情況下,任務(wù) A 和任務(wù) B異步進(jìn)行,根據(jù)需要從隊(duì)列中插入和刪除數(shù)據(jù)。任務(wù)掛起只在兩種情況下發(fā)生:隊(duì)列滿和隊(duì)列空。
科科君
小貼士:內(nèi)存池和隊(duì)列之間有一個(gè)重要的區(qū)別———內(nèi)存池讀取數(shù)據(jù)不會影響內(nèi)容,但是從隊(duì)列讀取時(shí)會“消耗”數(shù)據(jù),即破壞性操作(實(shí)際上這只是概念性看法,讀指針只是移到了下一個(gè)位置)。
隊(duì)列使用的概要
下方代碼清單給出了隊(duì)列使用的概要。 科科君 01 ? ?
/* 基礎(chǔ)API */
/* 1. 創(chuàng)建隊(duì)列 */
FOS_CreateQueue(QLength, QItemSize);
/* 2. 從隊(duì)列獲取消息 */
FOS_GetFromQueue(QName, AddOfQData, QwaitingTime);
/* 3. 向隊(duì)列發(fā)送消息 */
FOS_SendToQueue(QName, AddOfQData, QwaitingTime);
02 ? ?
/* 創(chuàng)建一個(gè)全局的隊(duì)列聯(lián)結(jié)發(fā)送任務(wù)A和接收任務(wù)B */
/* 使用RTOS提供的數(shù)據(jù)類型 */
FOS_QName GlobalQA2B;
FOS_QLength QA2Blength = 1;
FOS_ItemSize QA2BItemSize = 4;
GlobalQA2B = FOS_CreateQueue (QA2Blength, QA2BItemSize);
03 ? ?
/* 發(fā)送到隊(duì)列-任務(wù)A */
/* 使用RTOS提供的數(shù)據(jù)類型 */
long DataForQueueA2B;
const FOS_QwaitTime NoWaiting = 0;
FOS_ QloadStatus QLoadState;
QLoadState = FOS_SendToQueue (GlobalQA2B, &DataForQueueA2B, 0);
04 ? ?
/* 從隊(duì)列獲取-任務(wù)B */
/* 使用RTOS提供的數(shù)據(jù)類型 */
long DataFromQueueA2B;
const FOS_QwaitTime NoWaiting = 0;
FOS_QreadStatus QreadState;
審核編輯:黃飛
評論
查看更多