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 */
相关文章
相关标签/搜索