中科藍訊 BT8958B2 開發之 LVGL 線程安全

      哈嘍,大家好,最近筆者在使用中科藍訊 BT8958B2 開發板進行 Smart Watch 的 GUI 調試,這裡筆者使用的是 中科藍訊 BT8958B2 SDK 的 LVGL 版本,這個 SDK 中移植了 LVGL 7.11 版本,在這篇文章中跟大家分享一個開發中需要注意的點,關於 LVGL 線程安全的問題。

  • LVGL 默認不是線程安全

      在 LVGL 的官方文檔(Operating system and interrupts — LVGL documentation)中可以看到,默認情況下,LVGL 不是線程安全的,因此,在使用操作系統的時候,通常建議 LVGL 主要使用單線程去做,在多線程中使用 LVGL 可能會出現線程之間並發調用 LVGL 函數的問題,在 LVGL 官方文檔中給出的做法是在 lv_task_handler() 前加上互斥鎖,執行完lv_task_handler() 後釋放,並且在線程中調用每個 LVGL 相關函數都要加上相同互斥鎖,來避免並發調用的問題。回到中科藍訊 BT8958B2 的 SDK,SDK 中使用了 RT-Thread,操作系統大部分是原廠封裝在了底層中,但是還是可以看到,LVGL 的 lv_task_handler() 是放在了 gui_task_handler() 中,gui_task_handler() 屬於 SDK 中的 GUI 線程。


        

  • SDK 中單線程使用 LVGL

      GUI 線程主要在 gui_startup() 中創建並運行,在 SDK 中 GUI 線程的優先級比 Main 線程優先級高,但 GUI 線程默認被阻塞,分為 5ms、500ms 以及通過 GUI 線程消息隊列三種情況下觸發 GUI 線程,其中 gui_task_handler() 屬於 5ms 觸發一次的 GUI 線程的回調。

 

         

      SDK 中還有一個開發中主要使用到的線程,Main 線程;在使用 SDK 進行開發時,需要注意前面提到的避免並發調用 LVGL 函數,以初始化錶盤界面的 LVGL 控制項為例,可以在 Main 中通過 LVGL 的 lv_task_create() 創建錶盤控制項的初始化任務,在任務回調中去進行控制項的初始化,如下圖,gwatchface_refresh() 中做錶盤控制項的初始化,lv_task_once() 表示該任務僅運行一次,運行完成後會自動刪除(因為是初始化因此僅需執行一次,其他情況可按需求配置),通過這種方式創建的任務,會在 lv_task_handler() 中執行,因此 LVGL 相關函數的調用同樣是僅在 GUI 單一線程中完成的。

 

        



      前面提到過,GUI 線程默認被阻塞,但可以通過 GUI 線程消息隊列觸發 GUI 線程運行,同樣以錶盤控制項的初始化為例,可以在 Main 函數中發送 GUI 隊列消息,來執行錶盤控制項的初始化,如下圖中,通過 os_mq_gui_post_manual() 發送錶盤控制項初始化消息到 GUI 消息隊列。

 

         

      在接收消息隊列的回調函數中添加對該消息的處理,即對螢幕控制項的初始化,這樣一來, 整個 LVGL 的函數調用也還是在 GUI 線程中完成的。

 
        

      根據以上兩種方式大家可以根據在開發過程中的需求來選擇適合的方式,可以避免在多處使用互斥鎖的操作,但是需要注意,這裡僅是去實現單一線程來完成 LGVG 函數的調用,當線程中使用到一些多線程的共享數據時,還是需要添加對數據操作添加互斥鎖,今天的分享就到這裡,如果文章中有錯誤或者遺漏還望大家指出更正,相互學習。


[1] LVGL 官方文檔         Welcome to the documentation of LVGL! — LVGL documentation

★博文內容均由個人提供,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★文明上網,請理性發言。內容一周內被舉報5次,發文人進小黑屋喔~

評論