架構設計 生產者 消費者模式 第5頁 環形緩衝區

2021-06-19 21:09:31 字數 1379 閱讀 1763

正文:[3]:環形緩衝區

前乙個帖子提及了佇列緩衝區可能存在的效能問題及解決方法:環形緩衝區。今天就專門來描述一下這個話題。

為了防止有人給咱扣上「過度設計」的大帽子,事先宣告一下:只有當儲存空間的分配/釋放非常頻繁並且確實產生了明顯的影響,你才應該考慮環形緩衝區的使 用。否則的話,還是老老實實用最基本、最簡單的佇列緩衝區吧。還有一點需要說明一下:本文所提及的「儲存空間」,不僅包括記憶體,還可能包括諸如硬碟之類的 儲存介質。

★環形緩衝區 vs 佇列緩衝區

◇外部介面相似

在介紹環形緩衝區之前,咱們先來回顧一下普通的佇列。普通的佇列有乙個寫入端和乙個讀出端。隊列為空的時候,讀出端無法讀取資料;當佇列滿(達到最大尺寸)時,寫入端無法寫入資料。

對於使用者來講,環形緩衝區和佇列緩衝區是一樣的。它也有乙個寫入端(用於push)和乙個讀出端(用於pop),也有緩衝區「滿」和「空」的狀態。所以,從佇列緩衝區切換到環形緩衝區,對於使用者來說能比較平滑地過渡。

◇內部結構迥異

雖然兩者的對外介面差不多,但是內部結構和運作機制有很大差別。佇列的內部結構此處就不多囉嗦了。重點介紹一下環形緩衝區的內部結構。

大夥兒可以把環形緩衝區的讀出端(以下簡稱r)和寫入端(以下簡稱w)想象成是兩個人在體育場跑道上追逐(r追w)。當r追上w的時候,就是緩衝區為空;當w追上r的時候(w比r多跑一圈),就是緩衝區滿。

為了形象起見,去找來一張圖並略作修改,如下:

從上圖可以看出,環形緩衝區所有的push和pop操作都是在乙個固定的儲存空間內進行。而佇列緩衝區在push的時候,可能會分配儲存空間用於儲存新元 素;在pop時,可能會釋放廢棄元素的儲存空間。所以環形方式相比佇列方式,少掉了對於緩衝區元素所用儲存空間的分配、釋放。這是環形緩衝區的乙個主要優 勢。

★環形緩衝區的實現

如果你手頭已經有現成的環形緩衝區可供使用,並且你對環形緩衝區的內部實現不感興趣,可以跳過這段。

◇陣列方式 vs 鍊錶方式

環形緩衝區的內部實現,即可基於陣列(此處的陣列,泛指連續儲存空間)實現,也可基於鍊錶實現。

陣列在物理儲存上是一維的連續線性結構,可以在初始化時,把儲存空間一次性分配好,這是陣列方式的優點。但是要使用陣列來模擬環,你必須在邏輯上把陣列的 頭和尾相連。在順序遍歷陣列時,對尾部元素(最後乙個元素)要作一下特殊處理。訪問尾部元素的下乙個元素時,要重新回到頭部元素(第0個元素)。如下圖所 示:

使用鍊錶的方式,正好和陣列相反:鍊錶省去了頭尾相連的特殊處理。但是鍊錶在初始化的時候比較繁瑣,而且在有些場合(比如後面提到的跨程序的ipc)不太方便使用。

◇讀寫操作

環形緩衝區要維護兩個索引,分別對應寫入端(w)和讀取端(r)。寫入(push)的時候,先確保環沒滿,然後把資料複製到w所對應的元素,最後w指向下乙個元素;讀取(pop)的時候,先確保環沒空,然後返回r對應的元素,最後r指向下乙個元素。

架構設計 生產者 消費者模式 4 雙緩衝區

雙緩衝區 是乙個應用很廣的手法。該手法用得最多的地方想必是螢幕繪製相關的領域 主要是為了減少螢幕閃爍 另外,在裝置驅動和工控方面,雙緩衝也經常被使用。不過今天要聊的,並不是針對上述的某個具體領域,而是側重於併發方面的同步 互斥開銷。為啥要雙緩衝區 記得前幾天在介紹佇列緩衝區時,提及了普通佇列緩衝區的...

架構設計 生產者 消費者模式 4 雙緩衝區

雙緩衝區 是乙個應用很廣的手法。該手法用得最多的地方想必是螢幕繪製相關的領域 主要是為了減少螢幕閃爍 另外,在裝置驅動和工控方面,雙緩衝也經常被使用。不過今天要聊的,並不是針對上述的某個具體領域,而是側重於併發方面的同步 互斥開銷。為啥要雙緩衝區 記得前幾天在介紹佇列緩衝區時,提及了普通佇列緩衝區的...

架構設計 生產者 消費者模式 4 雙緩衝區

雙緩衝區 是乙個應用很廣的手法。該手法用得最多的地方想必是螢幕繪製相關的領域 主要是為了減少螢幕閃爍 另外,在裝置驅動和工控方面,雙緩衝也經常被使用。不過今天要聊的,並不是針對上述的某個具體領域,而是側重於併發方面的同步 互斥開銷。為啥要雙緩衝區 記得前幾天在介紹佇列緩衝區 時,提及了普通佇列緩衝區...