加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 1、問題背景
    • 2、軟件架構(gòu)問題
    • 3、軟件問題的分析與解決
    • 4、非技術(shù)性問題
    • 5、結(jié)語
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

嵌入式軟件的問題分析

2023/04/27
2294
閱讀需 28 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

1、問題背景

一切為了進度,軟件開發(fā)的首要目標就是以最快的速度滿足客戶需求,“快”是第一要素,但是短期指標;可復(fù)用性、擴展性等長期指標被忽略,導(dǎo)致后期的維護、功能增減調(diào)整都非常困難。一個小的業(yè)務(wù)需求會牽一發(fā)而動全身,一個小的故障修復(fù)可能引入更多的問題。整個系統(tǒng)包袱越來越沉重,軟件的質(zhì)量和開發(fā)周期越來越不可控。

排除軟件開發(fā)人員的水平和項目進度的原因,主要影響因素還包括軟件架構(gòu),和軟件缺陷的修復(fù)能力。對于量產(chǎn)軟件,架構(gòu)問題是先天性的,后期很難大改,只能前期預(yù)防;軟件缺陷問題是無法避免的,只能期望快速修復(fù)。拋磚引玉,也可先參看《嵌入式軟件bug從哪來,怎么去》。

2、軟件架構(gòu)問題

2.1 軟件架構(gòu)的特點

1. 承載力

正如一艘船最多能裝多少人,從軟件方面來說是軟件架構(gòu)能承載多少業(yè)務(wù)或功能需求,當(dāng)然,這需要架構(gòu)師一開始架構(gòu)系統(tǒng)的時候,就需要有一定的預(yù)見性。但也沒必要為了極小概率事件增加過多的冗余。

2. 易用性

易用性決定了軟件的整體開發(fā)效率,好的架構(gòu)會讓團隊成員容易上手,子系統(tǒng)容易對接,開發(fā)效率高,各模塊和子系統(tǒng)的編寫只需要關(guān)注系統(tǒng)的設(shè)計和編碼工作,其他模塊間通信方面的事情架構(gòu)可以提供很好的兼容。

3. 擴展性

一個水杯除了用來喝水,也可用來喝酒,適應(yīng)不同場景,在一定范圍內(nèi)滿足不同的需求,是非常有必要的。軟件架構(gòu)也是這樣,要新增更多的功能就要具備更高的擴展性??蓴U展性的關(guān)鍵就在于新增部分不能影響其他,如果增刪導(dǎo)致系統(tǒng)整體使用異常,那么這個架構(gòu)的可擴展性就很差。

4. 伸縮性

伸縮性就是設(shè)計的方案或系統(tǒng)是否可以根據(jù)需求適配不同數(shù)量的功能或子系統(tǒng),在我們設(shè)計的軟件系統(tǒng)中,架構(gòu)的可伸縮性決定了架構(gòu)的可適配性,例如,當(dāng)硬件資源不足時,可以調(diào)整配置如flash的空間分配,支持減少一些服務(wù)但仍能正常運行。

5. 容錯性

軟件運行中的異常,如用戶的非法操作,或者軟件本身的小缺陷導(dǎo)致整個系統(tǒng)無法使用,那這個架構(gòu)容錯性就很差。軟件中的一些缺陷無法避免,但是我們應(yīng)盡量保證這個缺陷的影響范圍最小。倘若出現(xiàn)系統(tǒng)無法使用的情況,應(yīng)該有備份方案,比如自動重啟或者自動恢復(fù)數(shù)據(jù)等功能,也應(yīng)該能夠讓開發(fā)人員及時知道問題的發(fā)生,以及問題所在的位置并記錄錯誤信息。

在架構(gòu)設(shè)計中,以上五項基本能力缺一不可,某項能力的突出并不能帶動其他項,如果某一項能力比較弱,隨著時間的推移,問題會越來越大,甚至系統(tǒng)崩潰。就像木桶原理那樣,一個木桶的容量不是取決于最長的那根木板,而是取決于最短的那根。

2.2 如何規(guī)劃軟件架構(gòu)

2.2.1 必須熟悉業(yè)務(wù)

軟件是為業(yè)務(wù)服務(wù)的,業(yè)務(wù)才是“目的”,軟件系統(tǒng)是為了達成業(yè)務(wù)系統(tǒng)目標的手段和方法。適應(yīng)當(dāng)前的業(yè)務(wù)需求是基礎(chǔ),充分考慮和預(yù)測未來的業(yè)務(wù)擴展,根據(jù)業(yè)務(wù)的擴展性來設(shè)計軟件的擴展性。如果可預(yù)見未來沒有擴展重大新業(yè)務(wù)的需求,那么相應(yīng)的軟件架構(gòu)就沒有必要采用高擴展的軟件架構(gòu)。比如嵌入式的傳感器數(shù)據(jù)采集小設(shè)備,就沒有必要把云計算等,業(yè)務(wù)范圍不沾邊的技術(shù)點放到其中。軟件架構(gòu)必須以服務(wù)業(yè)務(wù)為核心思想,不熟悉當(dāng)前軟件業(yè)務(wù)、和未來業(yè)務(wù)的擴展的架構(gòu)師是很難設(shè)計出好的軟件架構(gòu)。

2.2.1 借鑒業(yè)內(nèi)成熟的架構(gòu)

不照搬,并不意味著不要借鑒。借鑒業(yè)內(nèi)成熟的軟、硬件架構(gòu)是相對穩(wěn)妥、高效的做法。以業(yè)內(nèi)的架構(gòu)為基礎(chǔ),根據(jù)自身業(yè)務(wù)的特點,進行適配、裁剪和增加新的功能。熟悉業(yè)內(nèi)常規(guī)的、成熟的、最新的軟件架構(gòu)是架構(gòu)師的一項基本功。但熟悉并不是意味著必須立即在目標系統(tǒng)中實施這些軟件架構(gòu)。

2.2.3 采用設(shè)計模塊

設(shè)計模式(Design pattern)代表了最佳實踐,設(shè)計模式是軟件開發(fā)人員在開發(fā)過程中對一般問題的解決方案;是一套被反復(fù)使用的、多數(shù)人知曉的代碼設(shè)計經(jīng)驗的總結(jié),經(jīng)過相當(dāng)長的一段時間的試驗和錯誤總結(jié)出來的。

使用設(shè)計模式是為了重用代碼、讓代碼更容易被他人理解、保證代碼可靠性,合理地運用設(shè)計模式可以完美地解決很多問題。每種模式在現(xiàn)實中都有相應(yīng)的原理來與之對應(yīng),每種模式都描述了一個在我們周圍不斷重復(fù)發(fā)生的問題,以及該問題的核心解決方案,這也是設(shè)計模式能被廣泛應(yīng)用的原因。

用設(shè)計模式構(gòu)建一個新的軟件模塊時,短期會讓人感覺有多此一舉的味道;但中長期來看,設(shè)計模式能夠克服“壞”架構(gòu)的特征。學(xué)習(xí)這些模式有助于經(jīng)驗不足的開發(fā)人員通過一種簡單快捷的方式來學(xué)習(xí)軟件設(shè)計。盡管設(shè)計模塊通常被有經(jīng)驗的面向?qū)ο蟮能浖_發(fā)人員所采用,但是嵌入式軟件C語言也可以借鑒,參考《嵌入式軟件的設(shè)計模式(上),《嵌入式軟件的設(shè)計模式(下)》。

2.2.4 合理的橫向和縱向切分

橫向切分 :從硬件、驅(qū)動、組件到業(yè)務(wù)層,軟件分層隔離。如數(shù)據(jù)通信:PHY/MAC/IP/TCP/應(yīng)用層

縱向切分 :根據(jù)業(yè)務(wù)處理流程的環(huán)節(jié)縱向切分,不同的環(huán)節(jié)為不同的模塊,不同的業(yè)務(wù)功能為不同的模塊,如socket網(wǎng)絡(luò)、GNSS衛(wèi)星定位

2.2.5 按樹形結(jié)構(gòu)組織

按照樹形結(jié)構(gòu)的方式組織軟件系統(tǒng),不同的大功能拆分為小功能,文件夾內(nèi)套文件夾的實現(xiàn)形式,命名上統(tǒng)一,方便按功能快速找到對應(yīng)的源碼。

2.2.6 降低模塊之間的耦合度

耦合性是一種軟件度量,是指一程序中模塊及模塊之間信息或參數(shù)依賴的程度;內(nèi)聚性是一個和耦合性相對的概念,一般而言低耦合性代表高內(nèi)聚性,反之亦然。

2.2.7 降低模塊與模塊之間通信

一個軟件內(nèi)模塊與模塊之間的通信,構(gòu)成了一個內(nèi)部的通信網(wǎng),避免內(nèi)部模塊的通信采用網(wǎng)狀結(jié)構(gòu),這種解決方案是設(shè)計模式中的中介者模式。

2.3 重構(gòu)和演進架構(gòu)

架構(gòu)不能一成不變,要隨著業(yè)務(wù)需求的演進而升級重構(gòu),一成不變的架構(gòu)是危險的,總有一天架構(gòu)成為業(yè)務(wù)演進的最嚴重的制約因素。

這種需要實際開發(fā)中除完成既定的項目外,預(yù)留部分人力進行架構(gòu)升級維護,持續(xù)小改動,不定期根據(jù)業(yè)務(wù)的需求進行架構(gòu)的重構(gòu),未雨綢繆。

3、軟件問題的分析與解決

嵌入式軟件由于調(diào)試手段的限制、部署場景的多樣化、軟硬件問題混合在一起、外部環(huán)境因素的影響等因素,導(dǎo)致軟件經(jīng)常會遇到一些非常難以解決的問題。

3.1 解題思想

熟悉軟件的業(yè)務(wù)流程:從業(yè)務(wù)的角度發(fā)現(xiàn)問題、復(fù)現(xiàn)問題并解決問題。

熟悉軟件的總體架構(gòu):軟件架構(gòu)是解決難題問題的基本框架,基于軟件架構(gòu)解決問題不會陷入到局部細節(jié),導(dǎo)致修復(fù)一個問題的同時產(chǎn)生新的問題,不會犯原則性、方向性錯誤。

熟悉軟件代碼的實現(xiàn):熟悉代碼的細節(jié),能夠更好、更快的在蛛絲馬跡中找到證據(jù)和突破點,甚至在問題還沒有收斂前,提供一種收斂的方向,引領(lǐng)問題的解決,對代碼的熟悉程度直接關(guān)系到解決問題的速度。

3.2 調(diào)試手段和信息不足相關(guān)問題

3.2.1 現(xiàn)場偶發(fā)性、難復(fù)現(xiàn)性引發(fā)的問題

一些偶發(fā)性現(xiàn)象級問題,甚至導(dǎo)致系統(tǒng)偶發(fā)性的重啟,無法復(fù)現(xiàn),設(shè)備重啟之后,故障消失后,再也很難復(fù)現(xiàn)。

1、分析日志文件

從log中尋找異常提示,是應(yīng)對不可重復(fù)性、偶發(fā)性故障最基本的手段。在系統(tǒng)某處發(fā)生異常時,一定會在log中留下蛛絲馬跡,可以請客戶協(xié)助提供串口日志,在log文件中查找問題?;蛘咴O(shè)備自己內(nèi)部記錄log,但嵌入式設(shè)備由于存儲空間的限制,可能先前過于久遠的信息,就會被新的信息被覆蓋,針對這種情況,就需要定期清除無效日志。有些異常會導(dǎo)致系統(tǒng)重啟,而重啟之后,就會導(dǎo)致異常信息被正常重啟的信息覆蓋,這就需要系統(tǒng)能夠支持log的備份。不管怎么樣,log為定位現(xiàn)場問題提供了最基本的、最主要的信息來源。一個完善的log機制,對于定位現(xiàn)場問題非常有幫助。如果不滿足,可能首要任務(wù)是先完善日志功能。

2、回退軟件版本,緊急消除現(xiàn)場問題

有些現(xiàn)場問題,雖然偶發(fā)事件,但發(fā)生后影響嚴重,客戶無法接受。針對這種情況,在解決問題之前,可以先把軟件降級,降級到相對穩(wěn)定,沒有嚴重故障的版本。

3、比較相鄰版本之間的代碼改動

如果不容易復(fù)現(xiàn)的故障,確認在升級了某個軟件版本之后才出現(xiàn)的,而其他現(xiàn)場條件都沒有變化,且分析log也無法發(fā)現(xiàn)異常點。此時,一種高效的解決此問題的方法,就是比較兩個版本之間的代碼的改動。

代碼改動比較少,分析代碼比較容易;如果代碼改動比較多,就需要根據(jù)用戶描述的現(xiàn)象,結(jié)合前后代碼的改動模塊,初步分析最可能是哪個模塊引起的,這種往往需要對系統(tǒng)架構(gòu)較深刻的理解。在眾多修改模塊中,分析最有可能關(guān)聯(lián)的代碼模塊的改動,然后逐一排查 。分析代碼的改動與出現(xiàn)的現(xiàn)象之間可能的關(guān)聯(lián)關(guān)系,對開發(fā)人員個人的技術(shù)素養(yǎng)和方法論有較高的要求 。比較相鄰版本之間的代碼改動,針對某些棘手的現(xiàn)場問題,有時候確實是一個非常有效的手段。

4、問題復(fù)現(xiàn)

雖然常規(guī)來說現(xiàn)場很難復(fù)現(xiàn),但可以人為的修改軟件、構(gòu)建或增加模擬數(shù)據(jù),人為創(chuàng)造或觸發(fā)條件,增加故障復(fù)現(xiàn)的幾率。在設(shè)計觸發(fā)條件時,需要圍繞用戶描述的現(xiàn)場故障現(xiàn)象來設(shè)計觸發(fā)條件,觀察是否能否復(fù)現(xiàn),且表現(xiàn)一致。

5、分析代碼

根據(jù)用戶描述的現(xiàn)象,硬分析代碼,是一種通用的方法,放之四海皆準的方法,熟悉自身代碼的邏輯關(guān)系是基本功,但解決問題的效率就比較難把握了。

6、增加 log 更新版本繼續(xù)測

如果常規(guī)的log無法展現(xiàn)故障的異常,就需要在猜測有可能的部分增加日志,在現(xiàn)場復(fù)測。但這種日志添加的位置是否合理,決定了問題再次出現(xiàn)時是否能定位問題的準確性。這種方法在工程實踐中,實施難度大,需要客戶多次配合。

3.2.2 現(xiàn)象與真正的原因不在一起的問題

大多時候解決軟件故障,是可以做到頭痛醫(yī)頭,腳痛醫(yī)腳。有些時候,頭痛的原因并不在“頭”,而在“腳”。這就需要知道“頭痛” 與 “腳” 的某種關(guān)聯(lián)關(guān)系。

解決這樣的問題,對技術(shù)人員的綜合技能的要求非常高,因為這個問題,不再是局部問題,而是發(fā)散到調(diào)查該問題的技術(shù)人員不熟悉的其他的軟件組件領(lǐng)域。即使對于熟悉整個系統(tǒng)的人而言,也是一個難點,因為問題的現(xiàn)象與根源之間的路徑是發(fā)散的,沒有一個確切的路徑。

首先,必須以故障的表面現(xiàn)象作為錨點,作為出發(fā)點。為后續(xù)進一步的調(diào)查立一個基點。根據(jù)現(xiàn)象找到出問題的代碼,根據(jù)代碼和log分析代碼的表面原因。如果確實是本處代碼的問題,直接在此解決即可。即頭痛醫(yī)頭,腳痛醫(yī)腳。

很多情形下,真正的原因不在顯示異常的地方,比如收到了異常的事件、或參數(shù)不合理、或自身狀態(tài)機的問題等。這時候就需要追溯,為什么會有這樣的事件或消息?有時候,由于復(fù)雜系統(tǒng)的程序員沒有系統(tǒng)的視角,常以為消除了故障表面現(xiàn)象就是解決了問題。很多時候站在系統(tǒng)的視角,可以從多個層面加以解決,消除異常事情,可以從規(guī)則過濾模塊解決,也可從前置模塊或后續(xù)模塊解決。具體在哪兒解決最合理,這就需要有系統(tǒng)和結(jié)構(gòu)的視角。當(dāng)然,也曾遇到有人解決類似問題是屏蔽異常消息或者屏蔽ASSERT,并沒從根源去消除為什么產(chǎn)生了異常。

3.2.3 報錯點發(fā)生在第三方庫內(nèi)部

軟件報錯的地方是在第三方庫,而第三方庫有沒有源代碼或不熟悉

如果集成的第三方庫沒有源代碼,則把這個問題上報給第三方,讓第三方給出內(nèi)部出錯的原因,更新庫或者配合抓日志分析。如果第三方庫有源代碼的話,可分析第三方代碼,增加日志或檢查傳入第三方庫函數(shù)的參數(shù)是否正確,是否合法;大多數(shù)時候,是錯誤地傳入了不合適的參數(shù)給第三方庫。檢查使用第三方的時序是否正確,在軟件系統(tǒng)中,時序是一個非常重要,同樣的函數(shù),同樣的代碼,如果時序不對,也會導(dǎo)致代碼邏輯紊亂。不過現(xiàn)在提供庫或者SDK,一般都有技術(shù)支持,也可直接尋求幫助。

3.2.4 軟硬件結(jié)合導(dǎo)致的無法定位的問題

嵌入式系統(tǒng)中,有時候會出現(xiàn)硬件異常導(dǎo)致軟件狀態(tài)或邏輯錯誤,硬件人員很難根據(jù)有限的信息判斷硬件到底怎么了,通常軟件和硬件就會反復(fù)的踢皮球。但是用戶角度看到的異常是在軟件這邊。

由于硬件團隊對客戶現(xiàn)場的設(shè)備,通常沒有檢測手段來判斷是否真是硬件問題的,軟件團隊最好能夠通過日志配置,確認硬件故障單元?;蛘咧苯訉臋C寄回硬件部門,軟件配合復(fù)現(xiàn)問題,以幫助硬件團隊判斷。

硬件故障問題,需要特別關(guān)注供電、時鐘信號,復(fù)位時間等,曾經(jīng)遇到幾次因為串口漏電出去導(dǎo)致外部傳感器復(fù)位異常的問題??傊浻布慕缓咸?,是容易扯皮的地方,這需要軟件人員也同時了解硬件的工作原理,在出故障時,能夠更好的判斷是軟件異常,還是硬件真的有故障。

還有一個商業(yè)上的問題,如果客戶感受到是硬件的問題,需要回收設(shè)備,會造成很大的經(jīng)濟損失。一般情況下是軟件想辦法規(guī)避異常,畢竟軟件復(fù)制不需要成本。

3.3 內(nèi)存與指針相關(guān)問題

3.3.1 隱性的內(nèi)存泄露問題

內(nèi)存泄漏(Memory Leak)是指程序中已動態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放,造成系統(tǒng)內(nèi)存的浪費,導(dǎo)致程序運行速度減慢甚至系統(tǒng)崩潰等嚴重后果。內(nèi)存泄露是一個嚴重的慢性病,不會立即展現(xiàn),但不知道未來的哪一天,所有的設(shè)備,會在相近的時間點爆發(fā)問題。

內(nèi)存泄漏還會導(dǎo)致系統(tǒng)意外的重啟,重啟的原因可能千奇百怪。因此,檢測和解決內(nèi)存泄漏,就顯得非常重要。

1. 泄漏的原因

內(nèi)存泄漏主要是發(fā)生在堆內(nèi)存分配方式中,即malloc方式中,申請的內(nèi)存沒有得到釋放,或者對應(yīng)的指針被被覆蓋,內(nèi)存直接泄漏。因為內(nèi)存泄漏屬于程序運行中的問題,無法通過編譯識別,主要在程序運行過程中來判別和診斷。

2. 動態(tài)檢測或監(jiān)控是否內(nèi)存泄露

監(jiān)控系統(tǒng)內(nèi)存,周期性監(jiān)控堆中可用內(nèi)存的大小,是檢測系統(tǒng)是否有內(nèi)存泄漏的最有效的手段。系統(tǒng)的內(nèi)存短期會隨著業(yè)務(wù)數(shù)據(jù)的變化而變化,但長期來看,可用的剩余可用內(nèi)存會圍繞一個中軸線上下波動,如果存在內(nèi)存泄漏,其剩余可用內(nèi)存隨隨著時間的推移逐漸減少。

3. 如何找到在哪兒內(nèi)存泄露

可以使用工具檢測代碼中有沒有靜態(tài)的內(nèi)存泄露,也可以在代碼中增加標記,檢測長期未釋放的堆是誰申請的,在代碼中查找??梢詤⒖嘉恼隆?strong>動態(tài)內(nèi)存管理及防御性編程》。

3.3.2 指針跑飛的問題

指針跑飛就是指針指向不正確的位置,指針未初始化或數(shù)組/指針越界訪問,導(dǎo)致系統(tǒng)崩潰。

指針跑飛是常見的問題,問題很嚴重,但解決起來其實并不難,指針跑飛系統(tǒng)crash時,如果平臺軟件會打印出函數(shù)調(diào)用棧、segment fault錯誤、代碼出錯的地方、coredump文件等信息。有了這些信息,再分析源代碼,其實是很容發(fā)現(xiàn)或找出當(dāng)前代碼中指針跑飛的原因的。

如果基于第三方的SDK開發(fā),指針跑飛直接就重啟,可能不會有任何提示,因此,最好能夠在編碼時就能夠提前預(yù)防,而不是等待程序跑飛之后再定位解決?。常見的手段:

1、熟悉和遵守代碼編寫規(guī)范,加強代碼的評審,把問題消滅在編碼階段。

2、靜態(tài)檢測工具對代碼進行檢測。

3、增加邊界性測試用例,一般指針異常是在邊界或異常情形下發(fā)生的。

4、增加異常場景的測試,異常場景是違反常規(guī)的測試場景,這些異常業(yè)務(wù)場景,能夠盡早shi發(fā)現(xiàn)隱藏的問題。

3.3.3 空指針的問題

空指針是“指針跑飛”的一種特殊情況,即指針為NULL,通常出現(xiàn)在指針用NULL值初始化后,在某些情況下沒有給指針賦值,就直接使用指針范圍內(nèi)存?;蛘呓邮蘸瘮?shù)返回的指針變量,忽略了函數(shù)返回NULL的情形。

在使用指針前,檢查指針是否為空,如果為空,在代碼中執(zhí)行異常處理流程,如打印出錯信息,或者ASSERT,這樣就可以避免引起更嚴重的問題,相對來說多使用一個if即可規(guī)避。

3.3.4 棧溢出導(dǎo)致的問題

棧溢出時會訪問不存在的RAM空間,造成代碼跑飛,這時無法得到溢出時的上下文數(shù)據(jù),也無法對后續(xù)的程序修改提供有用信息。

函數(shù)遞歸調(diào)用,系統(tǒng)要在棧中不斷保存函數(shù)調(diào)用時的現(xiàn)場和產(chǎn)生的變量,如果遞歸調(diào)用太深,就會造成棧溢出。函數(shù)內(nèi)局部數(shù)組變量的內(nèi)存空間過大,或者局部數(shù)組變量的下標范圍溢出,破壞了棧空間中的內(nèi)容。這種問題容易解決但初始不容易查到原因。如果是帶操作系統(tǒng)的,一般系統(tǒng)內(nèi)核會直接提示棧空間不足,將任務(wù)??臻g加大,或者不靜態(tài)分配,用malloc動態(tài)創(chuàng)建,從堆中分配的。平時編碼中禁止使用循環(huán)遞歸函數(shù)。

3.4 軟件時序設(shè)計相關(guān)的問題

時序問題是最容易出問題的地方,“時”代表時間順序和時效性,一旦執(zhí)行順序錯亂,或執(zhí)行過慢失去時效,就會導(dǎo)致錯誤。

3.4.1 消息的串行化處理

每個任務(wù)、線程,只能按順序的處理串行的消息,然而,其他線程發(fā)送過來的消息并不是串行發(fā)送的,不同線程都是并行、異步發(fā)送消息的,這會導(dǎo)致線程在沒有處理完一個消息,另一個消息又回來了。如何把外部的并發(fā)消息轉(zhuǎn)換成線程的串行處理呢?

每個任務(wù)、線程都應(yīng)有一個消息隊列,外部線程向消息隊列中發(fā)送數(shù)據(jù),目標線程從消息隊列中讀取消息,這樣所有的消息被串行在消息隊列中,線程就會串行的處理每個消息,只有當(dāng)一個消息處理完(函數(shù)調(diào)用返回)時,才會處理另一個消息。參考《嵌入式軟件的設(shè)計模式(上)》中的 第3.3節(jié)?“隊列模式”。

3.4.2 超時或消息丟失引發(fā)的問題

一個任務(wù)、線程給另一個任務(wù)、線程發(fā)送消息,等待對方的應(yīng)答,有時候?qū)Ψ矫?,發(fā)送時隊列滿發(fā)送失敗,或者接收方?jīng)]有處理回復(fù),等待一段時間后空閑了才處理該消息并應(yīng)答時,但對于發(fā)送方已經(jīng)超時。發(fā)送方超時,就需要進入異常處理。這里容易出問題,它可能會引發(fā)一連串的異常處理反應(yīng),也有可能影響后續(xù)的正常消息的處理。

消息丟失是必須考慮情況,發(fā)送方不能假設(shè)接收方一定能夠收到消息,也不能假設(shè)接收方一定能夠及時的回應(yīng),必須充分考慮到消息因為傳輸?shù)膯栴}丟失或?qū)Ψ矫?,沒有及時回應(yīng)的情形。

消息丟失就容易產(chǎn)生理論上該執(zhí)行的動作沒有執(zhí)行,或者消息里面動態(tài)內(nèi)存未釋放?;蛘呦⑻幚砺龑?dǎo)致對外設(shè)的控制延遲產(chǎn)生異常,曾經(jīng)出現(xiàn)共享單車鎖里面的馬達停止消息處理不及時導(dǎo)致車鎖無法再次上鎖。尤其處理通信時序要求嚴格,或外設(shè)控制要及時的場景需要注意。

3.4.3 性能本身問題

數(shù)據(jù)處理尤其是復(fù)雜算法耗時,導(dǎo)致消息處理不及時,最終對外設(shè)的控制或者通信交互時序狀態(tài)延遲,產(chǎn)生異常。這種只能優(yōu)化算法,或?qū)r序部分單獨特殊處理,不考慮設(shè)計模式保執(zhí)行效率?;蛘咴u估階段就選擇性能資源更佳的硬件方案。

3.5 異常處理不充分問題

軟件設(shè)計一般是考慮正常流程,然而實際運行中,并非是理想狀態(tài),系統(tǒng)總會遇到各種異常,健壯的系統(tǒng),能夠充分考慮到各種異常情況,一旦異常發(fā)生,程序也不會輕易崩潰。

超時:增加超時定時器事件以及事件處理,不能假設(shè)對方一定應(yīng)答消息。

空指針:不能假設(shè)一定能夠申請到內(nèi)存,要考慮到返回為NULL的情形,通過指針訪問內(nèi)存對象時需要及時的檢查指針是否為空。

并發(fā)訪問:在并發(fā)執(zhí)行的系統(tǒng)中,如果要訪問全局變量,不能假設(shè)只有一個線程訪問全局變量,需要通過鎖對全局共享資源進行加鎖,特別是要訪問全局的數(shù)據(jù)結(jié)構(gòu)。

消息隊列:不能假設(shè)消息隊列始終有效,要考慮消息隊列滿或空的情形。

設(shè)計:在軟件設(shè)計時就考慮軟件的異常處理機制,功能層面就支持異常記錄、售后調(diào)試的需求,而不是把這個工作留給編程人員。

4、非技術(shù)性問題

大規(guī)模系統(tǒng)中軟件會分割成無數(shù)個模塊,負責(zé)這些的開發(fā)人員來自不同的職能部門,這些部門又有著各自不同優(yōu)先級的任務(wù),而解決那些復(fù)雜的問題又需要這些部門的配合,才能找到真正的出錯原因和找到最終的解決方案?;蛟S最終解決問題的代碼僅僅在一個組件中,或許只有簡單的一兩行代碼,然而找到問題的原因并給定解決方案的過程卻是漫長、繁瑣的。

4.1 人員分配

在大規(guī)模分工的系統(tǒng)中,每個技術(shù)領(lǐng)域都是一群人負責(zé),解決問題效率與個人的技術(shù)能力有極大的關(guān)系。有些簡單技術(shù)問題,如果參與的不是合適的技術(shù)人員,例如人員的變動導(dǎo)致原來的軟件人員不再負責(zé)該軟件,那簡單的問題也變得復(fù)雜。正所謂“難者不會,會者不難”。技術(shù)是長期積累的過程,同一類問題不要頻繁的更換人員。

4.2 任務(wù)分配

復(fù)雜系統(tǒng)中,一個問題需要涉及到多個部門,一個程序員在某個環(huán)節(jié)上的放緩,導(dǎo)致基于這個前置條件的進度也跟著放緩,整個組織的執(zhí)行就會極大的降低,從宏觀上看,整個組織都很忙,但總體的效率卻很低。

按優(yōu)先級排序分配任務(wù),在一個高優(yōu)先任務(wù)完成前,不要處理其他任務(wù),降低程序員并發(fā)處理故障的個數(shù),否則“任務(wù)”切換的開銷就很大。高難度與低難度任務(wù)搭配,同時處理多個高難度問題,整體效率是下降的,而且一個延期會連鎖導(dǎo)致后續(xù)都延期。

4.3 項目分配

實現(xiàn)一個復(fù)雜功能,或者解決某個問題,往往可以在不同的子系統(tǒng)解決,各個子系統(tǒng)出于各自原因,都希望最終的解決方案不要放到自己的子系統(tǒng),希望推到其他子系統(tǒng)。此時,一般是地位低的子系統(tǒng)人員妥協(xié),即使其子系統(tǒng)的實現(xiàn)不是最佳方案,這種就看項目分配,需要具有一定技術(shù)背景和決策權(quán)的人協(xié)調(diào)。

5、結(jié)語

關(guān)于軟件問題的分析理論,也只是拾人牙慧。理論和實際存在較大差異,真正遇到軟件問題,這些方法并不一定靠譜。

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險等級 參考價格 更多信息
ST3215SB32768B0HSZA1 1 Kyocera AVX Components Quartz Crystal,

ECAD模型

下載ECAD模型
暫無數(shù)據(jù) 查看
ASFL1-12.000MHZ-ERS-T 1 Abracon Corporation XTAL OSC XO 12.0000MHZ HCMOS TTL
$1.28 查看
SIT1552AC-JE-DCC-32.768E 1 SiTime Corporation Clock Generator
$1.46 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

嵌入式系統(tǒng)開發(fā)技術(shù)交流,軟件開發(fā)的思路與方案共享,行業(yè)資訊的分享。