緩衝區設計 環形佇列

2021-06-21 14:12:50 字數 4157 閱讀 4722

目錄(?)

[+]

在程式的兩個模組間進行通訊的時候,緩衝區成為乙個經常使用的機制。

如上圖,寫入模組將資訊寫入緩衝區中,讀出模組將資訊讀出緩衝區。這樣使得:

緩衝區顯然不適合下面的情況:

佇列使用環形佇列,如上圖。環形佇列的特點是,不需要進行動態的記憶體釋放和分配,使用固定大小的記憶體空間反覆使用。在實際的佇列插入和彈出操作中, 是不斷交叉進行的,當push操作時,head會增加;而pop操作時,tail會增加。push的速度快的時候,有可能追上 tail,這個時候說明佇列已經滿了,不能再進行push的操作了,需要等待 pop 操作騰出佇列的空間。當 pop 的操作快,使得 tail 追上 head,這個時候說明佇列已空了,不能再進行 pop 操作了,需要等待 push 進來資料。

下面列出了乙個環形佇列類的的資料結構的源程式 。

[cpp]view plain

copy

/* loopque.h

author: zhangtao

date: july 26, 2009

*/# ifndef loopque_h

# define loopque_h

# include       

namespace xtl     

loopque_impl(int msize) : max_size(msize), _front(0), _rear(0), _size(0) {}  

_tp& front()   

void push(

const _tp& value)    

void pop()    

int check_pop(_tp& tv)    

int check_push(

const _tp& value)    

bool full() 

const    

bool empty() 

const   

int  size() 

const   

int  capacity() 

const   

private:  

int32_t _front;  // front index

int32_t _rear;   // rear index

int32_t _size;   // queue data record number

const int32_t max_size; 

// queue capacity

_tp  data[0];    // data record occupy symbol

};  

template

<

typename _tp>  

struct loopque_allocate    

void deallocate(

void *p)     

};  

template

typename _tp, typename alloc = loopque_allocate<_tp> >  

class loopque     

~loopque()    

value_type& front()   

const value_type& front() 

const   

void push(

const value_type& value)    

void pop()    

int check_pop(value_type& tv)    

int check_push(

const value_type& value)    

bool full() 

const    

bool empty() 

const   

int  size() 

const   

private:  

alloc alloc;  

loopque_impl<_tp>& impl;  

};  

} // end of 

# endif  // end of 

程式裡定義了兩個類 loopque_impl及loopqueue。前者定義了環形佇列的基本資料結構和實現,後者又進行了一次記憶體分配包裝。

21行的loopque_impl的建構函式是以佇列的空間大小作為引數建立這個類的。也就是說,在類建立的時候,就決定了佇列的大小。

63行中定義的佇列的陣列空間為 _tp data[0]。這似乎是乙個奇怪的事情。事實上,這個空間大小應該是max_size個陣列空間。 但由於max_size是在類建立的時候確定的,在這裡,data[0]只起到乙個佔位符的作用。所以,loopque_impl這個類是不能直接使用的, 需要正確的分配好記憶體大小,才能使用,這也是需要裡另外設計乙個類loopqueue的重要原因之一。也許您會奇怪,為什麼要這樣使用呢?如果定義乙個指標, 例如:_tp *data,然後在建構函式裡面使用 data = new _tp[max_size],不是很容易嗎?但是,不要忘記了,我們這個環形佇列類有可能會是乙個程序間共享類。 例如,乙個程序push操作,另乙個程序pop操作。這樣,這個類是需要建立在共享記憶體中的。而共享記憶體中的類的成員,如果包含有指標或者引用這樣的型別, 將給記憶體分配帶來很大的麻煩。而我們這樣以這個佔位符的方式設計這個類,將減少這種麻煩和複雜性。

17行的addsize的類函式確定了loopque_impl需要的另外的記憶體空間的大小。

loopqueue顯示了怎樣使用loopque_impl,解決記憶體分配問題的。從79行的模版引數中,我們看到,除了緩衝區資料存放型別_tp的引數外,還有乙個alloc型別。 這便是用於分配loopque_impl記憶體空間使用的模版類。

在loopqueue的成員中,定義了loopque_impl的乙個引用 impl(102行)。這個引用便是指向使用alloc分配空間得來的loopque_impl的空間。

alloc模版引數有乙個預設的定義值 loopque_allocate。從這個預設的分配記憶體的類裡,我們可以看到乙個分配loopque_impl的實現樣例,見69行:

char *p = new char[sizeof(loopque_impl<_tp>) + loopque_impl<_tp>::addsize(msize)];

return *(new (p) loopque_impl<_tp>(msize));

這裡,先根據msize分配好了靠慮到了data[msize]的足夠的記憶體,然後,再使用定位的new操作,將loopque_impl建立在這個記憶體區中。這樣,loopque_impl類就可以使用它其中的 _tp data[0]的成員。實際上,這個成員已經有 _tp data[msize]這樣的空間了。 這裡,如果我們設計另外乙個分配記憶體的類,例如,loopque_shmalloc。這個類是使用共享記憶體,並在其中建立loopque_impl類。這樣我們就可以使用:

loopque<_tp loopque_shmalloc>

來建立乙個可以在程序間共享而進行通訊的環形佇列類了。

至此,我們可以總結一下:這些工作我們將在隨後的設計中進行。且聽下回分解。

附件: loopque的測試程式:

[cpp]view plain

copy

/* tst-loopque.cpp

test program for class

author: zhangtao

date: july 27, 2009

*/# include       

# include       // for function

# include       "xtl/loopque.h"

intmain(int argc, 

char **argv)  

queue.check_push(1000);  

std::cout <

<

" size:"

<

for ( 

int i = 0; i 

std::cout <

<

" size:"

<

return 0;  

}   

環形緩衝區 環形緩衝佇列學習

專案中需要執行緒之間共享乙個緩衝fifo佇列,乙個執行緒往佇列中添資料,另乙個執行緒取資料 經典的生產者 消費者問題 開始考慮用stl的vector容器,但不需要隨機訪問,頻繁的刪除最前的元素引起記憶體移動,降低了效率。使用linklist做佇列的話,也需要頻繁分配和釋放結點記憶體。於是自己實現乙個...

環形緩衝區

include include include include include define buffsize 1024 1024 define min x,y x y x y pthread mutex t lock pthread mutex initializer struct cycle b...

環形緩衝區

define print buf size 16 1024 static char g pcnetprintbuf 環形緩衝區的首位址 static int g ireadpos 0 環形緩衝區讀的位置 static int g iwritepos 0 環形緩衝區寫的位置 intinit 判斷環形緩...