本發(fā)明屬于緩沖方法,具體涉及一種用循環(huán)隊列緩沖數(shù)據(jù)的方法。
背景技術(shù):
通信和信號處理領(lǐng)域經(jīng)常要用到的數(shù)據(jù)緩沖。由于數(shù)據(jù)接收和處理往往不是同頻同步,需要有一個足夠大的緩沖區(qū)來緩沖數(shù)據(jù)。一般用隊列來緩沖數(shù)據(jù)。
隊列是一種常用的線性表數(shù)據(jù)結(jié)構(gòu),在一端插入數(shù)據(jù),在另一端刪除數(shù)據(jù),就是我們常說的fifo。
用鏈表的方式實現(xiàn)涉及到動態(tài)內(nèi)存分配,效率較低,而且在很多嵌入式應(yīng)用中無法實現(xiàn)。用數(shù)組的方式,由于緩沖區(qū)大小有限且位置固定,每次數(shù)據(jù)更新都要移動已經(jīng)收到的數(shù)據(jù)。如果緩沖區(qū)大小為n,那么最不利的情況下隊列數(shù)據(jù)更新的時間復(fù)雜度為o(n)。在n很大的時候,會占用很多cpu的寶貴時間。
技術(shù)實現(xiàn)要素:
本發(fā)明針對現(xiàn)有技術(shù)的缺陷,提供一種用循環(huán)隊列緩沖數(shù)據(jù)的方法。
本發(fā)明是這樣實現(xiàn)的:一種用循環(huán)隊列緩沖數(shù)據(jù)的方法,包括下述步驟:
步驟一:建立隊列
建立能夠增加長度,也能夠減少長度的隊列,
步驟二:數(shù)據(jù)的存取
當(dāng)有新數(shù)據(jù)存入隊列時,首先增加隊列頭對應(yīng)的地址,然后在該地址內(nèi)存入相應(yīng)數(shù)據(jù);
當(dāng)有數(shù)據(jù)被讀取出隊列時,首先將隊列尾的數(shù)據(jù)輸出,然后增加隊列尾對應(yīng)的地址,
步驟三:地址循環(huán)使用
將隊列的標(biāo)志和隊列標(biāo)志對應(yīng)的地址分開處理。
如上所述的一種用循環(huán)隊列緩沖數(shù)據(jù)的方法,其中,所述的步驟一中設(shè)置兩個標(biāo)志位,一個標(biāo)志位表示隊列的頭,一個標(biāo)志位表示隊列的尾,當(dāng)需要增加隊列長度時,增加隊列頭對應(yīng)的地址,當(dāng)需要減小隊列的長度時,增加隊列尾對應(yīng)的地址。
如上所述的一種用循環(huán)隊列緩沖數(shù)據(jù)的方法,其中,所述的步驟一中,表示隊列頭的標(biāo)志位的數(shù)值大于標(biāo)志隊列尾的標(biāo)志位的數(shù)值。
如上所述的一種用循環(huán)隊列緩沖數(shù)據(jù)的方法,其中,所述的步驟一中設(shè)置隊列長度。
如上所述的一種用循環(huán)隊列緩沖數(shù)據(jù)的方法,其中,所述的步驟三當(dāng)隊列標(biāo)志對應(yīng)的地址溢出時,將該地址指定為隊列最初的地址位,但是隊列標(biāo)志的序號仍按照原規(guī)則增加,此處的隊列標(biāo)志表哭隊列頭標(biāo)志位和隊列尾標(biāo)志位。
如上所述的一種用循環(huán)隊列緩沖數(shù)據(jù)的方法,其中,由于標(biāo)志位為32位無符號整型,最大存儲量為4g。
本發(fā)明的效果是:通過將標(biāo)志位與地址分開處理,使得本來有限的隊列長度可以無限循環(huán)使用,隊列使用的限制由原來的隊列長度轉(zhuǎn)變?yōu)殛犃袠?biāo)志位的數(shù)值最大限制,極大的增加了硬件利用率。而且該方法并不針對某一特定數(shù)據(jù)處理過程,因而無論操作系統(tǒng)還是應(yīng)用程序,都可以使用該方法優(yōu)化,所有優(yōu)化累計起來的效果是巨大的。
具體實施方式
一種用循環(huán)隊列緩沖數(shù)據(jù)的方法,包括下述步驟:
步驟一:建立隊列
建立能夠增加長度,也能夠減少長度的隊列。
設(shè)置兩個標(biāo)志位,一個標(biāo)志位表示隊列的頭,一個標(biāo)志位表示隊列的尾,當(dāng)需要增加隊列長度時,增加隊列頭對應(yīng)的地址,當(dāng)需要減小隊列的長度時,增加隊列尾對應(yīng)的地址。
設(shè)置時,表示隊列頭的標(biāo)志位的數(shù)值大于標(biāo)志隊列尾的標(biāo)志位的數(shù)值。
另外設(shè)置隊列長度。
步驟二:數(shù)據(jù)的存取
當(dāng)有新數(shù)據(jù)存入隊列時,首先增加隊列頭對應(yīng)的地址,然后在該地址內(nèi)存入相應(yīng)數(shù)據(jù);
當(dāng)有數(shù)據(jù)被讀取出隊列時,首先將隊列尾的數(shù)據(jù)輸出,然后增加隊列尾對應(yīng)的地址。
步驟三:地址循環(huán)使用
由于計算機給隊列的存儲空間大小是固定的,而上述數(shù)據(jù)存取時,地址均是增加的,因而無論隊列空間多大,都會出現(xiàn)地址溢出的情況。如果將地址溢出對應(yīng)的標(biāo)志循環(huán)回最初地址位時,又會產(chǎn)生隊列頭和隊列尾無法區(qū)分的問題。
將隊列的標(biāo)志和隊列標(biāo)志對應(yīng)的地址分開處理,即
當(dāng)隊列標(biāo)志對應(yīng)的地址溢出時,將該地址指定為隊列最初的地址位,但是隊列標(biāo)志的序號仍按照原規(guī)則增加。此處的隊列標(biāo)志表哭隊列頭標(biāo)志位和隊列尾標(biāo)志位。
例如設(shè)隊列頭標(biāo)志位用index1表示,對應(yīng)的地址用a表示,隊列尾標(biāo)志位用index2表示,對應(yīng)地址用b表示,隊列長度為n,隊列最初的地址位為z,
那么,當(dāng)index1對應(yīng)的地址a溢出時,將a指定為z,但是index1++的執(zhí)行內(nèi)容不變,同理當(dāng)index2對應(yīng)的地址b溢出時,將b指定為z,但是index2++的執(zhí)行內(nèi)容不變。此時隊列的長度為index1-index2,每個地址卻不是順次給出的地址位了,此時只需要根據(jù)標(biāo)志位對應(yīng)的地址進行存取,那么數(shù)據(jù)便不會產(chǎn)生錯誤。
由于標(biāo)志位一般為32位無符號整型,因而最大存儲量為4g。
下面給出更為詳細的解釋說明。
設(shè)隊列的長度為n,隊列緩沖區(qū)為q[n],用index1表示數(shù)據(jù)的插入索引標(biāo)號,用index2表示數(shù)據(jù)的刪除索引標(biāo)號。插入數(shù)據(jù)操作可以簡單的表示成:
q[index1++]=newdata;
數(shù)據(jù)的刪除操作只需要增加index2標(biāo)號就可以了。比如我們要把數(shù)據(jù)存入文件,可以寫成函數(shù)為:
save_to_file(q[index2++]);
當(dāng)index2小于index1的時候,表示隊列中有數(shù)據(jù),可以讀出來。當(dāng)index2等于index1的時候,表示隊列為空,等待數(shù)據(jù)插入。一般由兩個線程同時工作,分別完成數(shù)據(jù)的插入和讀取。
隊列插入線程可以寫成如下偽代碼:
隊列的讀取刪除線程可以寫成如下偽代碼:
由于n只能是有限大小,隨著數(shù)據(jù)不斷插入,index1和index2都會大于n,此時就會出現(xiàn)內(nèi)存溢出的問題了。
為此設(shè)計循環(huán)隊列存儲數(shù)據(jù)。我們能想到的做法是index大于等于n的時候,從隊列頭存取數(shù)據(jù)。每次index1、index2自加1的時候?qū)求余數(shù):
index=(index+1)%n;
這樣,當(dāng)index超出n的時候,又從隊列頭的開始了。然而這又帶來新的問題,就是會出現(xiàn)index2大于index1的情況了。這使得邏輯變得混亂。
考慮這樣的操作方式,index1、index2自加賦值的時候不對n求模,只在存取數(shù)據(jù)的時候求模。這樣能夠保證index2永遠不大于index1。
據(jù)此,隊列插入線程可以寫成如下偽代碼:
隊列的讀取刪除線程可以寫成如下偽代碼:
兩個線程的代碼還是保持了簡單的邏輯。每插入一個新的數(shù)據(jù)只需要一次寫入操作,每處理一個數(shù)據(jù)只需要一次讀取操作。保證了數(shù)據(jù)緩沖的高效性。
如果index1,index2的數(shù)據(jù)類型為32位無符號整型,可以存取的數(shù)據(jù)最多是4g,如果數(shù)據(jù)量比較大,可以將index1,index2的數(shù)據(jù)類型擴充為64位無符號整型。