目錄(?)
[+]
在程式的兩個模組間進行通訊的時候,緩衝區成為乙個經常使用的機制。
如上圖,寫入模組將資訊寫入緩衝區中,讀出模組將資訊讀出緩衝區。這樣使得:
緩衝區顯然不適合下面的情況:
佇列使用環形佇列,如上圖。環形佇列的特點是,不需要進行動態的記憶體釋放和分配,使用固定大小的記憶體空間反覆使用。在實際的佇列插入和彈出操作中, 是不斷交叉進行的,當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 判斷環形緩...