RT-Thread 內核學習筆記 - 內核對象rt_objecthtml
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 */