從零開始的激光通訊(軟件篇 第1章 協議棧)——2、環形數組

從零開始的激光通訊(軟件篇 第1章 協議棧)——2、環形數組

github

https://github.com/HaHaHaHaHaGe/mynetstack

簡介

在說明環形數組之前,先來看一看通常大家使用內存的方式
在這裏插入圖片描述
這是一段內存空間,大小16字節,起始地址0x80000000,截止地址0x8000000F

在這段內存中若想爲其內存空間進行賦值操作,C語言下應當:

*(unsigned char*)(0x80000000) = 0x66;

很明顯這條指令將0x66 賦值到了 0x80000000這個內存空間中

同樣你也可以:

unsigned char i = 16
while(i--)
	*(unsigned char*)(0x80000000 + i) = 0x66;

這樣你將把整個內存空間從 0x80000000 ~ 0x8000000F 全部賦值爲0x66,當然在現實應用中會賦值更有意義的數據,並非0x66

同樣你也可以讀取數組內的數據

unsigned char recv;
recv = *(unsigned char*)(0x80000000);

或者連續讀取內存中的數據

unsigned char recv[16];
unsigned char i = 16
while(i--)
	recv = *(unsigned char*)(0x80000000 + i);

啊~一切是那麼的美好,我可以隨意的存儲、寫入我希望的數據

好,接下來咱們在做一些假設:首先寫入的人不再是你,而是其他人(程序)
那麼這樣一來問題就變得有些複雜了,
你並不能知道,對方什麼時間會向裏面寫入數據

所以我需要有一個標誌來代表是否有人向內存中寫入了數據

然後輪詢的檢測這個標誌,若此標誌被置位了,則代表裏面有新的數據,需要讀取數據了

好的,問題解決了

但是這只是理想情況下,但在現實應用中,很可能當標誌被置位時,我沒有能力一口氣全部讀取新數據,這時候又該怎麼辦呢?

我們可以在增加一個標誌,這個標誌表示我讀到的位置,而之前的寫標誌也更改爲寫到的位置,這樣一來,就會變成下面的樣子:
在這裏插入圖片描述
當寫入方寫入數據時只需要挪動寫標誌,讀取方只是要挪動讀標誌

而且,我也只需要檢測讀寫標誌的距離就可知道當前是否有新的數據了

一切看似近乎完美,但是卻有一個致命的問題:
在這裏插入圖片描述
當寫位置達到末尾時,這時候該怎麼辦呢?

如果置之不理,那麼很明顯下一次寫入的位置將是未知區域!,這是很危險的,一個野指針的存在比空指針更加的危險。

這時候就到環形數組發揮功效的時候了
在這裏插入圖片描述
環形數組,顧名思義,就像他的名字一樣,結構是個環形,當讀\寫指針超過0x8000000F時也不會造成嚴重事故,因爲他被重定向到了0x80000000

這便是環形數組了,當然內存自己本身不可能從硬件修改成環形結構,環形的結構是在軟件層面上定義的

函數說明

有關環形數組的文件在\mynetstack\Source\BasicDataStream\inc 與\mynetstack\Source\BasicDataStream\src 中
名稱爲 ringbuffer.c 與 ringbuffer.h

注:程序還在更新,以GITHUB爲準

/*
寫數據到緩衝區函數
入口參數:
ptr:操作對象
data:寫入的數據指針
datalen:寫入的數據長度
*/
void write_buffer_data(ringbuffer *ptr, u8* data, u32 datalen);


/*
釋放緩衝區函數
注:如果在創建時指定了已經開闢好的內存,
那麼該函數只會清理此模塊內部的變量,
不會更改外部的數據
入口參數:
ptr:操作對象
*/
u8 deinitial_buffer(ringbuffer *ptr);




/*
創建緩衝區函數
注:可在創建時指定已經開闢好的內存,
入口參數:
ptr:操作對象
self_mem: 是否由本函數自行分配空間,如果不需要,
應輸入NO並在操作對象的start ptr中分配好相應的空間
size: 需要開闢空間的大小
*/
u8 initial_buffer(ringbuffer *ptr, u8 self_mem, u32 size);


/*
外部寫入數據後使用此函數更新內部參數
入口參數:
ptr:操作對象
datalen:外部寫入的數據長度
*/
void write_buffer_len(ringbuffer *ptr, u32 datalen);


/*
獲取全部未讀數據
入口參數:
ptr:操作對象
len: 讀出數據的長度(字節)
preview:若爲YES則此次讀取不會修改ringbuff內指針狀態
*/
u8* get_unread_data(ringbuffer *ptr, u32 *len,u8 preview);





/*
獲取全部未讀數據的指針(分兩部分)
入口參數:
ptr:操作對象
ptr_1: 保存第一個指針
ptr_2: 保存第二個指針
len_1: 第一個指針內容的大小(字節)
len_2: 第二個指針內容的大小(字節)
preview:若爲YES則此次讀取不會修改ringbuff內指針狀態
*/
void get_unread_ptr(ringbuffer *ptr, u8** ptr_1, u8** ptr_2, u32* len_1, u32* len_2, u8 preview);








/*
手動更新read指針
注:一般在get_unread_ptr後根據自身情況使用
入口參數:
ptr:操作對象
*/
void update_readlocation(ringbuffer *ptr);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章