環形緩衝區是生產者和消費者模型中常用的資料結構。生產者將資料放入陣列的尾端,而消費者從陣列的另一端移走資料,當達到陣列的尾部時,生產者繞回到陣列的頭部。如果只有乙個生產者和乙個消費者,那麼就可以做到免鎖訪問環形緩衝區(ring buffer)。寫入索引只允許生產者訪問並修改,只要寫入者在更新索引之前將新的值儲存到緩衝區中,則讀者將始終看到一致的資料結構。同理,讀取索引也只允許消費者訪問並修改。
環形緩衝區實現原理圖
如圖所示,當讀者和寫者指標相等時,表明緩衝區是空的,而只要寫入指標在讀取指標後面時,表明緩衝區已滿。
清單9. 2.6.10環形緩衝區實現**
/*需要注意的是* __kfifo_put - puts some data into the fifo, no locking version
* note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these functions.
*/ unsigned int __kfifo_put(struct kfifo *fifo,
unsigned char *buffer, unsigned int len)
/* * __kfifo_get - gets some data from the fifo, no locking version
* note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these functions.
*/ unsigned int __kfifo_get(struct kfifo *fifo,
unsigned char *buffer, unsigned int len)
使用ring_buffer_get(kfifo_get)或者ring_buffer_put(kfifo_put)時,如果返回引數與傳入引數len不相等時,則操作失敗
我們定義乙個
//注意student_info 共17位元組 按照記憶體排列佔24位元組
typedef struct student_info
student_info;
我們建立乙個環形緩衝區,裡面只有64位元組大小(雖然我們實際使用時大小遠大於此),向裡面多次存入24位元組student_info,看有什麼反應
//列印學生資訊void print_student_info(const student_info *stu_info)
student_info * get_student_info(time_t timer)
void print_ring_buffer_len(struct ring_buffer *ring_buf)
int main(int argc, char *ar**)
else
printf("\n");
//第一次呼叫時用位元組結束後還有64-24 =40位元組
stu_info = get_student_info(976686458);
oklen = ring_buffer_put(ring_buf, (void *)stu_info, student_len);
if(oklen==student_len)
else
print_ring_buffer_len(ring_buf);
printf("\n");
//第二次呼叫時用位元組結束後還有64-48 =16位元組
stu_info = get_student_info(976686464);
oklen= ring_buffer_put(ring_buf, (void *)stu_info, student_len);
if(oklen==student_len)
else
print_ring_buffer_len(ring_buf);
printf("\n");
//第三次呼叫時需要用位元組但只有位元組失敗
//把位元組都寫滿了
//驗證了在呼叫__kfifo_put函式或者__kfifo_get函式時,如果返回引數與傳入引數len不相等時,則操作失敗
stu_info = get_student_info(976686445);
oklen= ring_buffer_put(ring_buf, (void *)stu_info, student_len);
if(oklen==student_len)
else
print_ring_buffer_len(ring_buf);
printf("\n");
//第四次呼叫時需要用位元組但無位元組
驗證了在呼叫__kfifo_put函式或者__kfifo_get函式時,如果返回引數與傳入引數len不相等時,則操作失敗
stu_info = get_student_info(976686421);
oklen= ring_buffer_put(ring_buf, (void *)stu_info, student_len);
if(oklen==student_len)
else
print_ring_buffer_len(ring_buf);
printf("\n");
//現在開始取學生資料裡面儲存了個學生資料我們取三次看效果
printf("output student\n");
printf("\n");
//第一次取得資料並列印
memset(stu_info,0,student_len);
oklen=ring_buffer_get(ring_buf, (void *)stu_info, student_len);
if(oklen==student_len)
else
print_ring_buffer_len(ring_buf);
printf("\n");
第二次取得資料並列印
memset(stu_info,0,student_len);
oklen=ring_buffer_get(ring_buf, (void *)stu_info, student_len);
if(oklen==student_len)
else
print_ring_buffer_len(ring_buf);
printf("\n");
//第三次取得資料失敗
需要注意的地方:
1.只有乙個執行緒負責讀,另乙個執行緒負責寫的時候,資料是執行緒安全的。上面的實現是基於這個原理實現的,當有多個執行緒讀或者多個執行緒寫的時候,不保證資料的正確性。
所以使用的時候,乙個執行緒寫,乙個執行緒讀。網路應用中比較常用,就是開乙個執行緒介面資料,然後把資料寫入佇列。然後開乙個排程執行緒讀取網路資料,然後分發到處理執行緒。
2.資料長度預設巨集定義了乙個長度,超過這個長度的時候,後續的資料會寫入失敗。
使用無鎖佇列(環形緩衝區)注意事項
環形緩衝區是生產者和消費者模型中常用的資料結構。生產者將資料放入陣列的尾端,而消費者從陣列的另一端移走資料,當達到陣列的尾部時,生產者繞回到陣列的頭部。如果只有乙個生產者和乙個消費者,那麼就可以做到免鎖訪問環形緩衝區 ring buffer 寫入索引只允許生產者訪問並修改,只要寫入者在更新索引之前將...
環形緩衝區 環形緩衝佇列學習
專案中需要執行緒之間共享乙個緩衝fifo佇列,乙個執行緒往佇列中添資料,另乙個執行緒取資料 經典的生產者 消費者問題 開始考慮用stl的vector容器,但不需要隨機訪問,頻繁的刪除最前的元素引起記憶體移動,降低了效率。使用linklist做佇列的話,也需要頻繁分配和釋放結點記憶體。於是自己實現乙個...
fork 時緩衝區注意事項
fork 呼叫時,整個父程序空間會原模原樣複製到子程序中,包括指令 變數值 程式呼叫棧 環境變數和緩衝區等等。include include include intmain return0 輸出結果 a0a0 include include include intmain return0 輸出結果 ...