現代的C++編程在很大程度上將對底層CPU實際執行的二進制代碼的需求抽象化了。然而,這種抽象化在嵌入式系統中可能會導致穩定性問題,而許多開發人員并不一定意識到這個問題的嚴重性。本文旨在提供一些背景信息,解釋這一問題,并提出一些解決方案。
在早期,嵌入式設備的程序是用匯編語言編寫的。盡管這種方法提供了對底層硬件的精細控制,但它繁瑣、容易出錯,并且高度依賴于目標CPU的架構。隨著嵌入式系統中C編譯器的普及,開發人員迅速轉向了更高級的語言。
然而,放棄對底層機器的控制權是有代價的。程序員與底層機器和目標系統之間的距離變得更遠,對編譯器如何將源代碼轉換為執行指令的過程的控制也減少了。
內存分配和堆棧管理是一個重要的問題。在C程序中,應用程序員可以清楚地知道自己是否、在哪里以及如何使用堆棧。然而,在嵌入式系統中,中斷服務例程(ISR)是系統的一部分,這就引入了潛在的問題。
中斷服務例程中斷了正常的程序執行。如果ISR中執行了堆棧操作,而同時該堆棧操作又被中斷,就可能導致系統不穩定。例如,同一塊內存塊可能會被分配兩次,一次分配給請求它的ISR,另一次分配給請求它的正常程序。這種沖突會導致不可預測的行為,包括系統不穩定和崩潰。
然而,這個問題往往很難在測試階段發現,因為它往往是隨機發生的,且發生頻率較低。這意味著即使存在問題,也很難重現,從而使得問題在最終產品中出現,導致系統的不穩定性。
一旦問題的根源被確定,解決方案通常就變得更加明確了。以下是兩種可能的解決方法:
1、較困難的方法是確保應用程序不會在中斷服務例程中調用堆棧相關的函數。
這意味著在ISR中應僅使用C,并且要確保不調用alloc()或free()等可能觸發堆棧操作的函數。然而,這并不容易實現,因為ISR可能會調用其他函數,這些函數也必須保證是"無堆棧"調用的。此外,即使您的代碼能夠滿足這一要求,其他團隊成員引入的C++代碼可能會再次引發問題。因此,這種方法的實施較為困難。如果您決定采用這種方法,一個建議是,在調試構建中,通過在"Lock"例程中添加代碼段來檢查CPU的中斷狀態,從而確保內存管理例程不會從中斷上下文(ISR)中調用。這樣一來,如果存在問題,就可以在開發過程中發現并解決,而不會將問題帶入最終產品中。
2、簡單方法:在堆棧操作的關鍵部分禁用中斷。
在embedded studio中,這是默認行為,也就是說,在使用embedded studio進行開發時,這個問題就不存在了,它只是簡單地在運行!
此外,embedded studio還提供了另一種鎖定選項,名為“User”。

在這種情況下,用戶可以控制堆棧鎖定,以調整系統以適應多核CPU等應用程序。通過使用“User”選項,用戶可以根據特定需求對堆棧操作進行定制,以實現更高級別的性能優化和系統調整。這種靈活性的使用可以根據具體的應用場景和硬件配置來優化堆棧操作,確保系統在多核環境或高度時間關鍵的情況下能夠實現最佳性能。