RT-Thread 內核學習筆記 - 理解defunct殭屍線程

RT-Thread 內核學習筆記 - 內核對象rt_objecthtml

RT-Thread 內核學習筆記 - 內核對象管理app

RT-Thread 內核學習筆記 - 內核對象操做API學習

RT-Thread 內核學習筆記 - 內核對象初始化鏈表組織方式ui

RT-Thread 內核學習筆記 - 內核對象鏈表結構深刻理解url

RT-Thread 內核學習筆記 - 設備模型rt_device的理解.net

RT-Thread 內核學習筆記 - 理解defunct殭屍線程線程

前言

  • 目前你們偶爾會討論RT-Thread線程退出的問題,如main線程,return後,怎麼處理的?RAM等資源,是否獲得釋放。指針

  • 最近在看線程相關的內核源碼,基於內核對象rt_object管理方法,梳理一下線程退出後的處理流程。code

  • rt_thread_defunct,殭屍線程的鏈表結構,爲何叫【殭屍】,我查的字典。做用,回收刪除的線程的內存(堆)資源。htm

線程初始化與建立

  • rt_thread_init:靜態初始化一個線程,線程結構體、線程棧,都是全局的變量。rt_thread_detach後,這個線程的內核對象從內核容器鏈表裏移除,【但】線程結構體、線程棧,由於是靜態全局的,沒法釋放。若下次再想初始化並使用這個線程,依舊能夠使用這個detach後的現有的線程結構體、線程棧進行初始化。靜態線程的特色:初始化後,內存的佔用,就不會改變。

  • rt_thread_create:動態建立一個線程。須要使能:RT_USING_HEAP,堆管理。建立的線程【結構體】與【線程棧】都是動態申請出來的。刪除這個線程時,須要調用rt_thread_delete。刪除後,線程的【結構式】與【線程棧】佔用的內存(堆)空間,能夠釋放。刪除後,這個線程不存在了,想再次開啓使用,須要從新建立。動態線程的特色:刪除後,內存資源能夠釋放。

線程的資源回收

  • RT-Thread 只回收rt_thread_create的線程內存資源。

  • 靜態初始化或動態建立線程時,會註冊:rt_thread_exit,線程退出後,會調用rt_thread_exit。

  • rt_thread_exit中,第一步:把線程從調度鏈表移除。第二步:靜態的線程,會調用:rt_object_detach,從內核對象容器裏移除線程內核對象;動態線程,會把線程的結構體指針(操做句柄),加入rt_thread_defunct殭屍線程鏈表中,而不是當即釋放線程佔用的內存。殭屍線程的操做,是在idle線程中執行。第三步:執行線程調度,切換線程。在idle線程執行,應該是保證這個線程刪除後,當即調度切換線程,線程的資源回收不須要過高的優先級。

  • idle 線程中: rt_thread_idle_excute 負責查看rt_thread_defunct殭屍線程鏈表是否爲空,若是不爲空,則執行內存釋放的操做。從線程鏈表移除、釋放線程棧、釋放內核結構體。注意,只有動態建立的線程,執行此操做。

/* 來自:rt_thread_idle_excute 片斷 */

        /* remove defunct thread */
        rt_list_remove(&(thread->tlist));
        /* release thread's stack */
        RT_KERNEL_FREE(thread->stack_addr);
        /* delete thread object */
        rt_object_delete((rt_object_t)thread);

main線程退出

  • 上面梳理了線程的退出,殭屍線程的處理流程,main線程的退出,基本上也能夠梳理流程了

  • 靜態的main線程,未使能:RT_USING_HEAP,退出後,內存資源不會釋放。

  • 動態的main線程,使能了:RT_USING_HEAP後,退出後,內存資源獲得釋放。

  • 實際對比內存資源的釋放大小,發現,動態申請,會額外佔用一點內存資源,如12字節,這部分在後面內存管理後再深刻的梳理。

動態線程的資源回收:

RT_USING_HEAP main存在時:線程棧大小爲2048

msh >free
total memory: 89568
used memory : 10656
maximum allocated memory: 10656

main不存在時:

msh >free
total memory: 89568
used memory : 8456
maximum allocated memory: 10656

main的線程棧,return後的資源:2200 Bytes空間

2048 棧空間 + 12Byte(rt_malloc管理佔用)
128Byte rt_thread結構體大小,sizeof(struct rt_thread) + 12Byte(rt_malloc管理佔用,內核對象)。

合計:2048+12+128+12 = 2200。

總結

  • 熟悉RT-Thread線程的初始化、建立、脫離(反初始化)、刪除等操做。

  • 熟悉動態建立的線程,刪除後,加入殭屍線程鏈表,內存資源回收流程。

  • 理解普通線程如main線程的退出流程。

  • 帶着問題後續繼續研究如下知識點:

  • 調度器的工做流程,在哪裏執行?如何運做?

  • 線程定時器,每一個線程都會建立一個,線程刪除後,定時器資源的回收流程。

rt_thread_delete /* 線程的定時器,使用detach方式,定時器資源回收流程 */

rt_timer_detach(&(thread->thread_timer)); /* 定時器資源的回收流程 */
  • 建立線程時,我把線程的名字(name)改成RT_NULL,依舊能夠正常的運行,但這樣是否有影響?

  • rt_thread 結構體中:內核對象的鏈表用於加入內核對象容器,成員:tlist的工做流程。

  • 歷史問題:rt_thread結構體:

/**
* Thread structure
*/
struct rt_thread
{
   /* rt object */
   char        name[RT_NAME_MAX];                      /**< the name of thread */
   rt_uint8_t  type;                                   /**< type of object */
   rt_uint8_t  flags;                                  /**< thread's flags */

#ifdef RT_USING_MODULE
   void       *module_id;                              /**< id of application module */
#endif

   rt_list_t   list;                                   /**< the object list */

是否能夠改成以下:

/**
 * Thread structure
 */
struct rt_thread
{
    struct rt_object parent;                            /**< inherit from rt_object */
相關文章
相關標籤/搜索