環形緩衝區的實現原理

2021-06-29 13:34:59 字數 3990 閱讀 7651

在通訊程式中,經常使用環形緩衝區作為資料結構來存放通訊中傳送和接收的資料。環形緩衝區是乙個先進先出的迴圈緩衝區,可以向通訊程式提供對緩衝區的互斥訪問。

1、環形緩衝區的實現原理

環形緩衝區通常有乙個讀指標和乙個寫指標。讀指標指向環形緩衝區中可讀的資料,寫指標指向環形緩衝區中可寫的緩衝區。通過移動讀指標和寫指標就可以實現緩衝區的資料讀取和寫入。在通常情況下,環形緩衝區的讀使用者僅僅會影響讀指標,而寫使用者僅僅會影響寫指標。如果僅僅有乙個讀使用者和乙個寫使用者,那麼不需要新增互斥保護機制就可以保證資料的正確性。如果有多個讀寫使用者訪問環形緩衝區,那麼必須新增互斥保護機制來確保多個使用者互斥訪問環形緩衝區。

圖1、圖2和圖3是乙個環形緩衝區的執行示意圖。圖1是環形緩衝區的初始狀態,可以看到讀指標和寫指標都指向第乙個緩衝區處;圖2是向環形緩衝區中新增了乙個資料後的情況,可以看到寫指標已經移動到資料塊2的位置,而讀指標沒有移動;圖3是環形緩衝區進行了讀取和新增後的狀態,可以看到環形緩衝區中已經新增了兩個資料,已經讀取了乙個資料。

2、例項:環形緩衝區的實現

環形緩衝區是資料通訊程式中使用最為廣泛的資料結構之一,下面的**,實現了乙個環形緩衝區:

/*ringbuf .c*/

#include

#include

#define nmax 8

int iput = 0; /* 環形緩衝區的當前放入位置 */

int iget = 0; /* 緩衝區的當前取出位置 */

int n = 0; /* 環形緩衝區中的元素總數量 */

double buffer[nmax];

/* 環形緩衝區的位址編號計算函式,如果到達喚醒緩衝區的尾部,將繞回到頭部。

*/int addring (int i)

/* 從環形緩衝區中取乙個元素 */

double get(void)

else

/* 向環形緩衝區中放入乙個元素*/

void put(double z)

else

printf(「buffer is full\n」);

}int main/* end switch */

}while(opera[0] != 』e』);

return 0;}

在can通訊卡裝置驅動程式中,為了增強can通訊卡的通訊能力、提高通訊效率,根據can的特點,使用兩級緩衝區結構,即直接面向can通訊卡的收發緩 沖區和直接面向系統呼叫的接收幀緩衝區。 通訊中的收發緩衝區一般採用環形佇列(或稱為fifo佇列),使用環形的緩衝區可以使得讀寫併發執行,讀程序和寫程序可以採用「生產者和消費者」的模型來 訪問緩衝區,從而方便了快取的使用和管理。然而,環形緩衝區的執行效率並不高,每讀乙個位元組之前,需要判斷緩衝區是否為空,並且移動尾指標時需要進行「折行處理」(即當指標指到緩衝區記憶體的末尾時,需要新將其定向到緩衝區的首位址);每寫乙個位元組之前,需要判斷緩區是否為,並且移動尾指標時同樣需要進行「折行處理」。程式大部分的執行過程都是在處理個別極端的情況。只有小部分在進行實際有效的操作。這就是軟體工程中所謂的「8比2」關係。結合can通訊實際情況,在本設計中對環形佇列進行了改進,可以較大地提高資料的收發效率。 由於can通訊卡上接收和傳送緩衝器每次只接收一幀can資料,而且根據can的通訊協議,can控制器的傳送資料由1個位元組的識別符號、乙個位元組的rtr 和dlc位及8個位元組的資料區組成,共10個位元組;接收緩衝器與之類似,也有10個位元組的暫存器。所以can控制器收的資料是短小的定長幀(資料可以不滿 8位元組)。 於是,採用度為10位元組的資料塊業分配記憶體比較方便,即每次需要記憶體緩衝區時,直接分配10個位元組,由於這10個位元組的位址是線性的,故不需要進行「折行」處理。更重要的是,在向緩衝區中寫資料時,只需要判斷一次是否有空閒塊並獲取其塊首指標就可以了,從而減少了重複性的條件判斷,大大提高了程式的執行效率;同樣在從緩衝佇列中讀取資料時,也是一次讀取10位元組的資料塊,同樣減少了重複性的條件判斷。 在can卡驅動程式中採用如下所示的稱為「block_ring_t」的資料結構作為收發資料的緩衝區:

typedef struct block_ring_t;

該資料結構在通用的環形佇列上增加了乙個資料成員usedbytes,它表示當前緩衝區中有多少位元組的空間被占用了。使用usedbytes,可以比較方 便地進行緩衝區滿或空的判斷。當usedbytes=0時,緩衝區空;當usedbytes=block_ring_buffer_size時,緩衝區 滿。本驅動程式除了收發緩衝區外,還有乙個接收幀緩衝區,接收幀佇列負責管理經hilon a協議解包後得到的資料幀。由於有可能要同接收多個資料幀,而根據can匯流排遙通訊協議,高優先順序的報文將搶占匯流排,則有可能在接收乙個低優先順序且被分為 好幾段傳送的資料幀時,被乙個優先順序高的資料幀打斷。這樣會出現同時接收到多個資料幀中的資料報,因而需要有個接收佇列對同時接收的資料幀進行管理。 當有新的資料報到來時,應根據addr(通訊位址),mode(通訊方式),index(資料報的序號)來判斷是否是新的資料幀。如果是,則開闢新的 frame_node;否則如果已有相應的幀節點存地,則將資料附加到該幀的末尾;在插入資料的同時,應該檢查接收包的序號是否正確,如不正確將丟棄這包 資料。 每次建立新的frame_node時,需要向frame_queue申請記憶體空間;當frame_queue已滿時,釋放掉隊首的節點(最早接收的但未完 成的幀)並返回該節點的指標。 當系統呼叫讀取了接收幀後,釋放該節點空間,使裝置驅動程式可以重新使用該節點。

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

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

佇列的讀寫需要在外部程序執行緒同步(另外寫了乙個rwguard類, 見另一文)

到專案的針對性簡單性,實現了乙個簡單的環形緩衝佇列,比stl的vector簡單

ps: 第一次使用模板,原來類模板的定義要放在.h 檔案中, 不然會出現連線錯誤。

template

class csharequeue 

//返回當前個數

unsigned int size()

//是否滿//warning: 需要外部控制資料一致性

bool isfull()

bool isempty()

protected:

uint m_head;

uint m_tail;

uint m_size;

uint m_capacity;

_type *pbuf;

};template

csharequeue<_type>::csharequeue() : m_head(0), m_tail(0), m_size(0)

template

csharequeue<_type>::csharequeue(unsigned int bufsize) : m_head(0), m_tail(0)

else

}template

csharequeue<_type>::~csharequeue()

//前面彈出乙個元素

template

_type csharequeue<_type>::pop_front()

_type itemtmp;

itemtmp = pbuf[m_head];

m_head = (m_head + 1) % m_capacity;

--m_size;

return itemtmp;

}//從尾部加入佇列

template

bool csharequeue<_type>::push_back( _type item)

pbuf[m_tail] = item;

m_tail = (m_tail + 1) % m_capacity;

++m_size;

return true;

}#endif // !defined(_daly_csharequeue_h_)

環形緩衝區的實現原理(ring buffer)

在通訊程式中,經常使用環形緩衝區作為資料結構來存放通訊中傳送和接收的資料。環形緩衝區是乙個先進先出的迴圈緩衝區,可以向通訊程式提供對緩衝區的互斥訪問。1 環形緩衝區的實現原理 環形緩衝區通常有乙個讀指標和乙個寫指標。讀指標指向環形緩衝區中可讀的資料,寫指標指向環形緩衝區中可寫的緩衝區。通過移動讀指標...

環形緩衝區的實現

乙個簡單的環形緩衝區,沒有寫加解鎖的部分,用於多執行緒的話還是自己加吧.pragma once include stdio.h include stdlib.h include memory.h namespace linker ring bool put elementtype e else bo...

環形緩衝區

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...