C 佇列與緩衝區

2021-09-24 10:27:51 字數 2975 閱讀 8703

最近在寫乙個資料互動模組,若本側收到資料後的處理是將其顯示到ui中(相對耗時),則當對側主動密集上報時,會出現一種情況:接收大量資料來不及處理的,這就有了生產者消費者不協調問題。多執行緒模式下,生產者和消費者模式是通過乙個容器來解決生產者和消費者的強耦合問題。生產者生產完資料後不用等待消費者處理,而是直接扔給阻塞佇列,消費者不找生產者要資料,而是直接從阻塞佇列中獲取資料。阻塞佇列就相當於乙個緩衝區(作用:解耦、支援併發、支援忙閒不均),平衡生產者和消費者的處理能力。

在併發執行緒中使用佇列緩衝區,有個繞不開的問題:假如生產者和消費者都很勤快,乙個主要的問題是關於記憶體分配的效能開銷。這時,環形緩衝區來了,他有較少的記憶體開闢和釋放開銷,不過,和執行緒中的佇列緩衝區類似,執行緒中的環形緩衝區也要考慮執行緒安全的問題。(引用自-環形緩衝區 vs 佇列緩衝區)

必須先來搞明白兩個概念,訊息佇列和訊息佇列中介軟體

訊息佇列及常見訊息佇列介紹

windows訊息佇列

還是回頭再去看看深入淺出mfc吧,記得裡頭有不錯的介紹來-

pthread_mutex_t 和 pthread_cond_t 配合使用 #

最讓我受益的是其流程圖的畫法,將pthread_cond_wait分解為3步操作,從在讓乙個跨執行緒的操作流變的相對很清晰。

激發條件有兩種形式,pthread_cond_signal()啟用乙個等待該條件的執行緒,存在多個等待執行緒時按入隊順序啟用其中乙個;而pthread_cond_broadcast()則啟用所有等待執行緒。

訊號量 互斥鎖 條件變數的區別 #

參考文獻

產品型訊息佇列的深入理解 #

linux迴圈訊息佇列 #

linux自定義訊息佇列 #

執行緒安全訊息佇列的設計思路 #

使用訊號量同步linux多執行緒 sem

在進行變長資料訊息佇列設計的過程中,我一直有個糾結,就是想千方百計的去減少資料拷貝過程,當然這種初衷肯定是好的,不過,此處涉及的記憶體拷貝過程,有想象中的那麼耗時嗎 ?

將驗證轉移到到記憶體的煩惱1中,最終的測試結論(不權威),在辦公pc(i5-4690 8g 3.5hz),平均大約memcpy 1 m資料量耗時1ms

在uart/socket通訊,從接收緩衝區中讀取資料,如果處理執行緒速率慢,那麼緩衝區會滿,繼而被覆蓋,從而造成資料的丟失。先看看socket緩衝區,在linux上其大小可以通過核心(驅動)配置檔案來改變;uart緩衝區也能通過介面來設定。

該章研究的是其上層的訊息緩衝,場景如下:從io緩衝區中讀取資料,經過幀協議解析,轉存到訊息佇列中,應用層從訊息佇列中按條讀取並處理(假定該處理較耗時),該訊息佇列也是一層緩衝區,滿了依然會丟失,不管這層緩衝是不是迴圈佇列,還是採取了什麼semaphore同步!這個過程中,我get到的緩衝區有3層:

i/o緩衝區或者叫系統緩衝區(不確定這麼叫是否合理!)

傳輸層經過協議解析後並組裝為實際意義的應用資料(不同的資料型別),我們暫且叫其資料互動層緩衝區(下稱commbuffer)

步驟2中的資料要分發到不同的地方進行使用(for me hmi-fresh),資料確實是處理過來,是可以進行特殊處理的,如直接拋棄舊資料顯示最新資料,如忽略新資料等策略。我們暫且叫這其具體資料緩衝區(下稱concretebuffer)

在繼續之前,有必要先再了解下,緩衝區意義何在?有篇部落格中,講了系統中默默工作的檔案輸出流,(寫檔案後flush你一定用到過(* ̄︶ ̄))談到了緩衝的意義、產生的問題、什麼時候用緩衝及緩衝策略。好了再回歸正題!我要實現緩衝區的原因:dev-b會給dev-a(我),主動上報資料(相同或不同),而且會有密集上報的情況發生,甚至在暈的會後會持續密集上報,我很糾結啊!

作為乙個嚴謹的程式猿,又在工業環境下,我們禁止資料悄無聲息的丟失,就算dev-b持續密集攻擊!資料處理不過來,誰該買賬,我的原則是,自己的事情自己做!主要有如下這麼幾點:

資料互動層不應該停下來等待應用層將資料處理完成

為應用層不同具體資料定製輸出緩衝策略,尤其要注意滿了後怎麼辦 ?

commbuffer不能滿,其執行在:應用層不進行任何處理時,模組處理能力,允許短暫密集資料出現,或短暫大資料出現!

concretebuffer允許滿,但必須提供處理手段並告知客戶,如「做過丟棄處理等」!其執行時支援,對持續密集資料的處理!

請補充一套環形緩衝區的執行示意圖。

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

環形緩衝區

任何收發兩端速度不一致的通訊,都需要在它們之間使用乙個足夠大的fifo緩衝區。可是多大是大,沒有最大,只有更大。

qt實現環形緩衝區的兩種方法

其他參考

不管是佇列緩衝區還是環形緩衝區,截止現在,沒有發現過有類似的實現,都是定長資料單元的。但是在c++中或qt中,我們可以通過std::queue 或者 qqueue來實現這種需求,如qqueue結構,但強迫症讓我覺得這很low啊!

在std和qt中一直沒發現可對外使用的環形緩衝區,qringbuffer雖然名字是對上了,但是並沒有體現出環形緩衝區較對聯緩衝區的優勢,它是存在記憶體的開闢和釋放的!

qt系統對signals的最大緩衝能力,超過會怎樣?因為之前遇到過,訊號堆積的情況,導致槽函式無法執行的情況!懷疑這也是造成hmi資料處理遠大於預估時間的原因之一!

結合在多執行緒程式設計分析-hmi假死、定時器碰撞多執行緒阻塞兩個小節的分析,可以基本的認為,如果沒有足夠處理時間,則訊號會堆積但不會丟失,當一有機會,就會一股腦一起執行,這個一股腦的執行相當於乙個耗時的操作,其影響的是這個執行緒內的其他執行過程的機會!

如果菜到不知道優先順序佇列是專有名詞,先看看百科-priority queue

生產與銷售的問題中,倉庫就是乙個緩衝區,能有效的吸收波動,很大程度上減少波動的傳遞,起到一種解耦作用,由強耦合變成一種鬆散耦合。

輸入緩衝區與輸出緩衝區

本博文通過一段程式來理解輸入緩衝區與輸出緩衝區。程式如下 author wanghao created time thu 17 may 2018 06 03 12 ampdt file name test.c description include int main int argc,const c...

緩衝區設計 環形佇列

目錄 在程式的兩個模組間進行通訊的時候,緩衝區成為乙個經常使用的機制。如上圖,寫入模組將資訊寫入緩衝區中,讀出模組將資訊讀出緩衝區。這樣使得 緩衝區顯然不適合下面的情況 佇列使用環形佇列,如上圖。環形佇列的特點是,不需要進行動態的記憶體釋放和分配,使用固定大小的記憶體空間反覆使用。在實際的佇列插入和...

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

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