使用無鎖佇列(環形緩衝區)注意事項

2021-09-24 18:19:55 字數 3982 閱讀 5631

環形緩衝區是生產者和消費者模型中常用的資料結構。生產者將資料放入陣列的尾端,而消費者從陣列的另一端移走資料,當達到陣列的尾部時,生產者繞回到陣列的頭部。如果只有乙個生產者和乙個消費者,那麼就可以做到免鎖訪問環形緩衝區(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 輸出結果 ...