2022-02-08 15:46:37|已瀏覽:3028次
錯誤1:競爭條件
競爭條件是指兩個或多個執(zhí)行線程(可以是RTOS任務(wù)或main() 和中斷處理程序)的組合結(jié)果根據(jù)交織指令的精確順序而變化的任何情況。每個都在處理器上執(zhí)行。
例如,假設(shè)您有兩個執(zhí)行線程,其中一個規(guī)則地遞增一個全局變量(g_counter + = 1; ),而另一個偶然將其歸零(g_counter = 0; )。如果不能始終以原子方式(即,在單個指令周期內(nèi))執(zhí)行增量,則存在競爭條件。最佳實踐:可以通過必須以適當?shù)膿屜认拗菩袨閷υ拥貓?zhí)行代碼的關(guān)鍵部分,來避免競爭條件。為防止涉及ISR的爭用情況,必須在另一個代碼的關(guān)鍵部分持續(xù)時間內(nèi)至少禁止一個中斷信號。
對于RTOS任務(wù)之間的爭用,最佳實踐是創(chuàng)建特定于該共享庫的互斥體,每個互斥體在進入關(guān)鍵部分之前必須獲取該互斥體。請注意,依靠特定CPU的功能來確保原子性不是一個好主意,因為這只能防止爭用情況發(fā)生,直到更換編譯器或CPU。
共享數(shù)據(jù)和搶占的隨機時間是造成競爭狀況的元兇。但是錯誤可能并不總是會發(fā)生,這使得從觀察到的癥狀到根本原因的種族狀況跟蹤變得異常困難。因此,保持警惕以保護所有共享對象非常重要。每個共享對象都是一個等待發(fā)生的事故。
最佳實踐:命名所有潛在共享的對象(包括全局變量,堆對象或外圍寄存器和指向該對象的指針),以使風(fēng)險對于所有將來的代碼閱讀者而言都是顯而易見的;在Netrino嵌入式C編碼標準提倡使用“的G_ 為此,”前綴。查找所有可能共享的對象將是爭用條件代碼審核的第一步。
錯誤2:不可重入功能
從技術(shù)上講,不可重入功能的問題是爭用狀況問題的特例。而且,由于相關(guān)原因,由不可重入函數(shù)引起的運行時錯誤通常不會以可重現(xiàn)的方式發(fā)生-使它們同樣難以調(diào)試。
不幸的是,非重入功能也比其他類型的競爭條件更難在代碼審查中發(fā)現(xiàn)。
為了可以同時從多個RTOS任務(wù)中調(diào)用此以太網(wǎng)驅(qū)動程序的功能,必須使它們可重入。如果它們每個僅使用堆棧變量,則無事可做。
因此,C函數(shù)最常見的樣式固有地是可重入的。但是,除非精心設(shè)計,否則驅(qū)動程序和某些其他功能將是不可重入的。
使函數(shù)可重入的關(guān)鍵是暫停對外圍設(shè)備寄存器,包括靜態(tài)局部變量,持久堆對象和共享內(nèi)存區(qū)域在內(nèi)的全局變量的所有訪問的搶占。這可以通過禁用一個或多個中斷或獲取并釋放互斥鎖來完成。問題的細節(jié)決定了最佳解決方案。
最佳實踐:在每個庫或驅(qū)動程序模塊中創(chuàng)建和隱藏一個互斥量,這些互斥量不是本質(zhì)上可重入的。使獲取此互斥鎖成為操作整個模塊中使用的任何持久數(shù)據(jù)或共享寄存器的前提。
例如,相同的互斥鎖可用于防止涉及以太網(wǎng)控制器寄存器和全局或靜態(tài)本地數(shù)據(jù)包計數(shù)器的競爭情況。在訪問這些數(shù)據(jù)之前,模塊中訪問此數(shù)據(jù)的所有功能必須遵循協(xié)議以獲取互斥量。
注意非重入功能可能會作為第三方中間件,舊版代碼或設(shè)備驅(qū)動程序的一部分進入您的代碼庫。
令人不安的是,不可重入函數(shù)甚至可能是編譯器隨附的標準C或C ++庫的一部分。如果您使用GNU編譯器來構(gòu)建基于RTOS的應(yīng)用程序,請注意您應(yīng)該使用可重入的“ newlib”標準C庫,而不是默認庫。
錯誤3:缺少volatile關(guān)鍵字
如果未使用C的volatile 關(guān)鍵字標記某些類型的變量,則可能導(dǎo)致僅在將編譯器的優(yōu)化器設(shè)置為低級或禁用編譯器才能正常工作的系統(tǒng)中出現(xiàn)許多意外行為。該揮發(fā)性預(yù)選賽期間變量聲明,其中它的目的是為了防止優(yōu)化的讀取和變量的寫入使用。
最佳實踐:將揮發(fā) 的關(guān)鍵字應(yīng)該用于聲明每個:
由ISR和代碼的任何其他部分訪問的全局變量,由兩個或多個RTOS任務(wù)訪問的全局變量(即使已阻止了這些訪問中的競爭條件),指向內(nèi)存映射外設(shè)寄存器(或一組或一組寄存器)的指針,以及延遲循環(huán)計數(shù)器。
請注意,除了確保所有讀寫操作都針對給定變量之外,使用volatile 還通過添加其他“序列點”來限制編譯器。除易失性變量的讀取或?qū)懭胫獾钠渌资栽L問必須在該訪問之前執(zhí)行。
錯誤4:堆棧溢出
每個程序員都知道堆棧溢出是很不好的事情。但是,每次堆棧溢出的影響都各不相同。損壞的性質(zhì)和不當行為的時機完全取決于破壞哪些數(shù)據(jù)或指令以及如何使用它們。重要的是,從堆棧溢出到它對系統(tǒng)的負面影響之間的時間長短取決于使用阻塞位之前的時間。
不幸的是,堆棧溢出比臺式計算機更容易遭受嵌入式系統(tǒng)的困擾。這有幾個原因,其中包括:
(1)嵌入式系統(tǒng)通常只能占用較少的RAM;
(2)通常沒有虛擬內(nèi)存可回退(因為沒有磁盤);
(3)基于RTOS任務(wù)的固件設(shè)計利用了多個堆棧(每個任務(wù)一個),每個堆棧的大小都必須足夠大,以確保不會出現(xiàn)唯一的最壞情況的堆棧深度;
(4)中斷處理程序可能會嘗試使用這些相同的堆棧。
使該問題進一步復(fù)雜化的是,沒有大量的測試可以確保特定的堆棧足夠大。您可以在各種加載條件下測試系統(tǒng),但是只能測試很長時間。僅在“半個藍月亮”中運行的測試可能不會見證僅在“一次藍月亮”中發(fā)生的堆棧溢出。在算法限制(例如無遞歸)下,可以通過對代碼的控制流進行自上而下的分析來證明不會發(fā)生堆棧溢出。但是,每次更改代碼時,都需要重做自上而下的分析。
最佳實踐:啟動時,在整個堆棧上繪制不太可能的內(nèi)存模式。(我喜歡使用十六進制23 3D 3D 23,它看起來像ASCII內(nèi)存轉(zhuǎn)儲中的籬笆' #==# '。)在運行時,讓管理員任務(wù)定期檢查是否沒有任何涂料在預(yù)先設(shè)定的高水位上方標記已更改。
如果發(fā)現(xiàn)某個堆棧有問題,請在非易失性內(nèi)存中記錄特定的錯誤(例如哪個堆棧以及洪水的高度),并為產(chǎn)品的用戶做一些安全的事情(例如,受控關(guān)閉或重置)可能會發(fā)生真正的溢出。這是添加到看門狗任務(wù)中的一項不錯的附加安全功能。
錯誤5:堆碎片化
嵌入式開發(fā)工程師并沒有很好地利用動態(tài)內(nèi)存分配。其中之一是堆碎片的問題。
通過C的malloc() 標準庫例程或C ++的new 關(guān)鍵字創(chuàng)建的所有數(shù)據(jù)結(jié)構(gòu)都駐留在堆中。堆是RAM中具有預(yù)定最大大小的特定區(qū)域。最初,堆中的每個分配都會減少相同字節(jié)數(shù)的剩余“可用”空間。
例如,特定系統(tǒng)中的堆可能從地址0x20200000開始跨越10 KB。一對4 KB數(shù)據(jù)結(jié)構(gòu)的分配將留下2 KB的可用空間。
可以通過調(diào)用free() 或使用delete 關(guān)鍵字將不再需要的數(shù)據(jù)結(jié)構(gòu)的存儲返回到堆中。從理論上講,這使該存儲空間可用于后續(xù)分配期間的重用。但是分配和刪除的順序通常至少是偽隨機的,這導(dǎo)致堆變成一堆更小的碎片。
若要查看碎片可能是一個問題,請考慮如果上述4 KB數(shù)據(jù)結(jié)構(gòu)中的第一個空閑時會發(fā)生什么情況。現(xiàn)在,堆由一個4 KB的空閑塊和另一個2 KB的空閑塊組成。它們不相鄰,無法合并。所以我們的堆已經(jīng)被分割了。盡管總可用空間為6 KB,但超過4 KB的分配將失敗。
碎片類似于熵:兩者都隨時間增加。在長時間運行的系統(tǒng)(換句話說,曾經(jīng)創(chuàng)建的大多數(shù)嵌入式系統(tǒng))中,碎片最終可能會導(dǎo)致某些分配請求失敗。然后呢?您的固件應(yīng)如何處理堆分配請求失敗的情況?
最佳實踐:避免完全使用堆是防止此錯誤的肯定方法。但是,如果動態(tài)內(nèi)存分配在您的系統(tǒng)中是必需的或方便的,則可以使用另一種結(jié)構(gòu)化堆的方法來防止碎片。
許多實時操作系統(tǒng)都具有固定大小的內(nèi)存池API。如果您可以訪問其中之一,請使用它代替malloc() 和free() ;蚓帉懽约旱墓潭ù笮〉膬(nèi)存池API。您只需要三個函數(shù):一個用于創(chuàng)建新的池(大小為M 塊N 字節(jié));另一個分配一個塊(來自指定的池);三分之一代替free() 。
代碼審查仍然是最佳實踐,
可以通過首先確保系統(tǒng)中不存在這些錯誤來避免許多調(diào)試麻煩。最好的方法是讓公司內(nèi)部或外部的人員進行全面的代碼審查。強制使用我在這里描述的最佳實踐的標準規(guī)則編碼也應(yīng)該會有所幫助。如果您懷疑現(xiàn)有代碼中存在這些討厭的錯誤之一,那么執(zhí)行代碼審查可能比嘗試從觀察到的故障追溯到根本原因要快。
注:尊重原創(chuàng)文章,轉(zhuǎn)載請注明出處和鏈接 http://m.universityresearchassociates.com/news-id-20027.html 違者必究!部分文章來源于網(wǎng)絡(luò)由培訓(xùn)無憂網(wǎng)編輯部人員整理發(fā)布,內(nèi)容真實性請自行核實或聯(lián)系我們,了解更多相關(guān)資訊請關(guān)注嵌入式開發(fā)頻道查看更多,了解相關(guān)專業(yè)課程信息您可在線咨詢也可免費申請試課。關(guān)注官方微信了解更多:150 3333 6050