緩衝區的設計

2021-07-27 15:54:12 字數 3878 閱讀 7875

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

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

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

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

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

/* 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

struct loopque_allocate    

void deallocate(void *p)     

};  

template >  

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的測試程式:

/* tst-loopque.cpp 

test program for class 

author: zhangtao 

date: july 27, 2009 

*/  

# include       

# include       // for function  

# include       "xtl/loopque.h"  

int  

main(int argc, char **argv)  

queue.check_push(1000);  

std::cout <

<

for ( int i = 0; i 

std::cout <

<

return 0;  

}   

php 緩衝區,PHP的輸出緩衝區

1 什麼是緩衝區?緩衝區的作用是把輸入或者輸出的內容先放進記憶體,而不顯示或者讀取,最本質的作用就是協調高速cpu和相對緩慢的io裝置 磁碟等 的運作。2 php在執行的時候,在什麼地方有用到緩衝區?當執行php的時候,如果碰到了echo print r之類的會輸出資料的 php就會將要輸出的資料放...

輸入緩衝區與輸出緩衝區

本博文通過一段程式來理解輸入緩衝區與輸出緩衝區。程式如下 author wanghao created time thu 17 may 2018 06 03 12 ampdt file name test.c description include int main int argc,const c...

緩衝區設計 環形佇列

目錄 在程式的兩個模組間進行通訊的時候,緩衝區成為乙個經常使用的機制。如上圖,寫入模組將資訊寫入緩衝區中,讀出模組將資訊讀出緩衝區。這樣使得 緩衝區顯然不適合下面的情況 佇列使用環形佇列,如上圖。環形佇列的特點是,不需要進行動態的記憶體釋放和分配,使用固定大小的記憶體空間反覆使用。在實際的佇列插入和...