如何在RTOS上全量支援C 11

2021-10-22 15:53:20 字數 3394 閱讀 4810

c語言自誕生以來已被廣泛應用於系統和應用開發。比如google的微核心作業系統fuchsia就是用c實現的,arm的嵌入式作業系統armmbed也主要基於c實現。在應用開發方面,c被廣泛用於gui、遊戲引擎、圖形引擎、瀏覽器引擎、資料庫等的開發。

c++語言的廣泛使用,得益於其如下特點:

(1)支援物件導向程式設計,封裝、繼承、多型等機制使程式設計更加高效。

(2)相容c,支援面向過程程式設計及驅動開發。

(3)標準庫支援豐富的檔案和資料結構操作。

(4)效能優異。

隨著mcu晶元處理能力的增強,嵌入式裝置的圖形顯示、模式識別、指令碼解析等能力不斷賦能裝置拓展應用邊界。同時,隨著應用的不斷拓展,對嵌入式裝置提出了更高的要求。通常,嵌入式系統採用c語言開發,但gui、ai演算法等複雜應用採用c開發,為此在rtos上支援c語言的需求變得越來越強烈。

有些rtos封裝系統介面為上層應用提供了自定義的c類,但由於這些類不符合c標準,基於這些類開發的應用缺乏可移植性。另一方面,當使用外部開源軟體時,需要進行適配,若軟體比較複雜,適配工作量比較大,更為災難性的是,自定義的類由於不夠全,往往很難滿足上層軟體的需要。所以,最可行的方法還是要支援標準c++庫。

說明:本篇文章基於物聯網作業系統alios things上c++11實踐總結而成,已在智慧型音箱等場景中應用。

對c語言而言,只能用常量或常量表示式初始化全域性變數,比如不允許呼叫函式初始化,也不允許用另乙個全域性變數初始化。也即是說,全域性變數的值在編譯時就確定了。另外對於全域性陣列,其長度在編譯時也確定了。

編譯器將未賦初值的全域性變數放在bss段,有初始值的全域性變數放在data段(唯讀資料放到rodata段)。當rtos啟動時,bss段全部清為0,從程式映象中讀取data段的內容並寫入到對應data段的記憶體,這樣就完成了所有全域性變數的初始化。

引入c++後,有了物件的概念,這個時候rtos啟動過程中的初始化就不再是清記憶體、拷貝記憶體那麼簡單了。物件內部的空間需要呼叫new分配,比如虛函式表、一些容器的內部儲存空間。同時,物件初始化過程中需要呼叫父類的建構函式。這些都無法在編譯時確定。

c處理這個問題的辦法是:把所有c原始檔中需要在初始化時呼叫的函式的位址集中放到乙個表中,rtos在初始化時遍歷該函式表並呼叫每乙個函式,以此完成c++物件的初始化。

rtos

啟動時,初始化c++物件的偽**如下:

for(f =

__ctors_start__

; f

<

__ctors_end__

; f++)

晶元廠商提供的要麼是基於linux的工具鏈,要麼是基於裸機的工具鏈(bare-metal)。在rtos上顯然只能選bare-metal工具鏈。所謂bare-metal,其含義是無作業系統平台,其執行緒模式為single,即無多執行緒併發。在這種模式下,不支援c的多執行緒,比如不支援mutex、thread、condition_variable等類,同時c庫內部實現中不考慮多執行緒互斥。所以這種模式下的工具鏈用在rtos上,一方面功能不全,另一方面存在穩定性隱患,尤其在多核平台上多執行緒併發問題將變得嚴重。因此,為了真正實現對c++11的全量支援,需針對rtos進行適配。

gcc工具鏈中整合了乙個c++庫,其依賴關係如下:

上圖中三個依賴部分說明如下:

適配主要涉及型別與介面兩部分,具體可參考./gcc/libgcc/gthr.**件。

c++內部型別

說明__gthread_t

執行緒型別

__gthread_key_t

執行緒內部變數

__gthread_once_t

單次執行

__gthread_mutex_t

互斥訊號量

__gthread_recursive_mutex_t

支援遞迴的互斥訊號量

__gthread_cond_t

條件變數

__gthread_time_t

時間c++內部介面

說明__gthread_active_p

返回1表示支援多執行緒,那麼c++庫內部的實現將考慮執行緒間臨界資源保護

__gthread_create

建立執行緒

__gthread_join

等待目標執行緒結束

__gthread_detach

執行緒狀態置為detached

__gthread_equal

判斷是否為同乙個執行緒

__gthread_self

獲得當前執行緒

__gthread_yield

讓出cpu

…………

用typedef把c內部型別定義為rtos的型別,基於rtos的介面實現上述適配介面,便完成了c庫的適配。如果rtos上已經完成了對posix介面的支援,那麼適配就比較方便了。示例如下:

//__gthread_t型別定義

typedef pthread_t __gthread_t;

//__gthread_create介面實現

static inline int

__gthread_create (__gthread_t *__threadid,  void *(*__func) (void*), void *__args)

在編譯c++庫時,需配置為使能多執行緒模式,主要配置項如下:

--enable-threads=posix

其實使能該選項只是觸發了配置指令碼檢查是否支援多執行緒,若配置指令碼執行過程中判斷系統不支援多執行緒,最終編譯出來的庫還是單執行緒的。比如,配置指令碼中對__gthreads_cxx0x巨集是否定義進行了判斷,若該巨集未定義則使能多執行緒失敗。

完成適配與配置後,重編工具鏈即可生成多執行緒版本的c庫。編譯完成後可檢視cconfig.**件,確認使能的c++特性。以_glibcxx_use_sched_yield巨集為例,若沒有生成該巨集,那麼thread類yield()函式實現為空函式、

得益於c++良好的封裝機制,用c++寫的**比用c寫的**bug率低很多。但硬幣的另一面是,除錯難度增加了。

即便開啟了編譯優化,c語言的一行語句與彙編的對應關係也相對比較清楚。但c++由於其複雜的機制,一行簡單的賦值語句往往會對應十幾條、甚至幾十條彙編。這需要rtos的維測能力提供高效的除錯支援。

dd windows 如何在Windows上dd?

dd windows ddis a handy tool on linux.but is it possible to run it on windows?dd是linux上的便捷工具。但是可以在windows上執行它嗎?i find theddin cygwin works very well f...

如何在細節上提高

所謂如何在細節上提高,就是我關注的就是能如何把自己的事情做的更加完美,也就前段時間對自己提出的嚴格要求所說的。我已經認識到了這是職業發展上面門檻,也是非常重要的一環。前幾天看書,書中提到了乙個表達邏輯的問題,就是乙個人要想把一件事情說清楚,要有兩個方面 就是說話格式上面的要求,說話要層次分明,重點突...

如何支援高訪問量

1.頁面靜態化或偽靜態 門戶 一般要面對巨大的訪問量。如果每次都是從資料庫中取資料的話 資料庫將面臨巨大的壓力 io讀寫也是乙個瓶頸。可以使用靜態頁面 把那些不經常改變的自動生成html檔案 緩解資料庫的壓力 比如新聞系統就可以使用。訪問大並且不經常更改的資料。2.資料庫讀寫分離 通過靜態化只能實現...