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 */