线程管理特点 线程属性 线程状态之间切换

线程管理特点 线程属性 线程状态之间切换 线程管理特点 线程属性 线程状态之间切换​ RT-Thread是支持多任务的操作系统多任务是通过多线程的方式实现。线程是任务的载体是RT-Thread中最基本的调度单位​ 线程在运行的时候它自己会认为自己独占CPU运行​ 线程执行时的运行环境成为上下文具体来说就是各个变量和数据包括所有寄存器变量堆栈内存信息等线程管理特点​ RT-Thread线程管理的主要功能是对线程进行管理和调度系统中总共存在两类线程系统线程和用户线程我们的重点是在用户线程,系统线程是由RT-Thread内核创建的线程用户线程是由应用程序创建的线程这两类线程都会从内核对象容器中分配线程对象当线程被删除时也会被从对象容器中删除。​ 内核对象容器 用双向链表做成的 “分类货架”用来收纳同一种类的所有内核对象方便内核增、删、挨个遍历检查。​ RT-Thread的线程调度器是抢占式的主要工作就是从就绪线程列表中查找最高优先级线程保证最高优先级的线程能够被运行最高优先级的任务一旦就绪总能得到CPU的使用权.​ 当调度器线程切换时先将当前线程上下文保存起来(保护现场)当再切回到这个线程时线程调度器将该线程的上下文信息恢复(恢复现场)。线程工作机制线程控制块(本质就是结构体)线程控制块是由结构体struct rt_thread表示线程控制块是操作系统用于管理线程的一个数据结构它会存放线程的一些信息例如优先级线程名称线程状态等也包含线程与线程之间连接用的链表结构线程等待事件集合等。/** * Thread structure */structrt_thread{/* rt object */charname[RT_NAME_MAX];/** 给线程起的名字是一个char 型的数组 */rt_uint8_ttype;/**type 定身份告诉我它是线程、定时器 还是别的资源RT-Thread 提前定义了一系列宏用不同数字代表不同对象类型举几个最常见的 #define RT_Object_Class_Thread 0x01 // 线程 #define RT_Object_Class_Timer 0x02 // 定时器 #define RT_Object_Class_Semaphore 0x03 // 信号量 #define RT_Object_Class_MessageQueue 0x04 // 消息队列 */rt_uint8_tflags;/** threads flags *//* flags 也是 1 字节8 个二进制位它不是存一个数字而是把每一个二进制位当成一个独立的 “开关” 特点动态变化。线程运行、挂起、退出这些状态切换本质就是 flags 里的 “开关” 在不断切换。 flags 主要记录两大类信息线程当前运行状态运行、就绪、挂起、关闭等 线程固有属性静态创建 / 动态创建、调度属性等 2. 结合线程状态讲解对应你 list_thread 的观测结果 我们之前看到线程有这些状态running、ready、suspend、closed全部由 flags 中的状态位来表示。 内核同样用宏定义每一个 “开关” 的含义节选常用状态标志 #define RT_THREAD_RUNNING 0x01 // 线程正在运行 #define RT_THREAD_READY 0x02 // 线程处于就绪态 #define RT_THREAD_SUSPEND 0x04 // 线程被挂起 #define RT_THREAD_CLOSE 0x08 // 线程已关闭退出 线程显示 running CPU 正在执行该线程flags 中 RT_THREAD_RUNNING 这一位置 1。 线程显示 suspend 比如 timer 线程、调用了 rt_thread_mdelay() 的线程RT_THREAD_SUSPEND 位置 1。 线程执行完 return 变为关闭态 RT_THREAD_CLOSE 位置 1同时 list_thread 会过滤掉这类线程。 3. 除了状态还存 “对象属性” flags 里除了运行状态还会标记线程的创建方式等固有属性 标记该线程是 静态线程rt_thread_init还是 动态线程rt_thread_create 标记线程是否允许被抢占、是否是系统内核线程等。 比如系统 timer、tidle0 是静态线程对应的属性位会固定置 1 你自己用 rt_thread_create 创建的线程动态属性位会置 1。 */#ifdefRT_USING_MODULEvoid*module_id;/** id of application module */#endif/* RT_USING_MODULE */rt_list_tlist;/** the object list */rt_list_ttlist;/** the thread list *//* 线程执行的核心(栈入口) */void*sp;/** 栈指针 线程上下文切换的核心:线程切出时CPU寄存器存在栈里sp保存当前栈顶地址*/void*entry;/** 线程入口函数 内核启动线程时从这个地址开始执行 */void*parameter;/** 入口函数的参数 类比一下就是rt_thread_create的第三个参数。一般传RT_NULL,这就是为什么入口参数要传带void*参数的原因内核会强制把这个字段传给入口 */void*stack_addr;/** 栈内存的起始地址 */rt_uint32_tstack_size;/** 栈大小 *//* error code */rt_err_terror;/** 线程错误码线程操作的返回值存在这里比如等待信号量超时 */rt_uint8_tstat;/** 线程状态核心调度字段: 0-初始状态(刚create还没有startup) 1-就绪态(等待调度) 2-运行态(正在CPU上跑) 3-挂起/阻塞态(延时等待资源) 4-关闭状态*//*单核MCU先不管.这个是SMP多核支持*/#ifdefRT_USING_SMPrt_uint8_tbind_cpu;/** thread is bind to cpu */rt_uint8_toncpu;/** process on cpu */rt_uint16_tscheduler_lock_nest;/** scheduler lock count */rt_uint16_tcpus_lock_nest;/** cpus lock count */rt_uint16_tcritical_lock_nest;/** critical lock count */#endif/*RT_USING_SMP*//* 优先级调度(RT-Thread实时调度的核心) */rt_uint8_tcurrent_priority;/** 线程当前优先级 *//*超过32级优先级时用*/#ifRT_THREAD_PRIORITY_MAX32rt_uint8_tnumber;rt_uint8_thigh_mask;#endif/* RT_THREAD_PRIORITY_MAX 32 */rt_uint32_tnumber_mask;/*事件集支持*/#ifdefRT_USING_EVENT/* thread event */rt_uint32_tevent_set;rt_uint8_tevent_info;#endif/* RT_USING_EVENT *//*信号支持*/#ifdefRT_USING_SIGNALSrt_sigset_tsig_pending;/** the pending signals */rt_sigset_tsig_mask;/** the mask bits of signal */#ifndefRT_USING_SMPvoid*sig_ret;/** the return stack pointer from signal */#endif/* RT_USING_SMP */rt_sighandler_t*sig_vectors;/** vectors of signal handler */void*si_list;/** the signal infor list */#endif/* RT_USING_SIGNALS */rt_ubase_tinit_tick;/**线程初始时的时间片 */rt_ubase_tremaining_tick;/** 剩余时间片 */#ifdefRT_USING_CPU_USAGErt_uint64_tduration_tick;/** cpu usage tick */#endif/* RT_USING_CPU_USAGE */#ifdefRT_USING_PTHREADSvoid*pthread_data;/** the handle of pthread data, adapt 32/64bit */#endif/* RT_USING_PTHREADS */structrt_timerthread_timer;/** built-in thread timer */void(*cleanup)(structrt_thread*tid);/** cleanup function when thread exit *//* light weight process if present */#ifdefRT_USING_LWPvoid*lwp;#endif/* RT_USING_LWP */rt_ubase_tuser_data;/** private user data beyond this thread */};typedefstructrt_thread*rt_thread_t;void (*cleanup)(struct rt_thread *tid);cleanup函数指针指向的函数会在线程退出的时候被Idle线程回调一次执行用户设置的清理现场等工作。线程状态线程属性线程栈​ RT-Thread线程具有独立的栈当进行线程切换时会将当前线程的上下文存入栈中(压栈)当要线程恢复运行时再从栈中读取上下文信息(出栈)进行恢复。线程状态**初始状态:**当线程刚开始创建rt_thread_create或rt_thread_init还没有开始运行的时候就处于初始状态。在初始状态下线程不参与调度。此状态在RT-Thread中的宏定义为RT_THREAD_INIT就绪状态:在就绪状态下线程按照优先级排队等待被执行一旦当前线程运行完毕让出处理器操作系统会马上寻找最高优先级的就绪态线程运行。此状态在RT-Thread中的宏定义为RT_THREAD_REDAY**运行状态:线程当前正在运行。在单核系统中只有rt_thread_self()**函数返回的线程处于运行状态在多核系统中可能就不止这一个线程处于运行状态。此状态在RT-Thread中的宏定义为RT_THREAD_RUNNING**挂起状态:**也称阻塞态。它可能因为资源不可用而挂起等待或线程主动延时一段时间而挂起。在挂起状态下线程不参与调度。此状态在RT-Thread中的宏定义为RT_THREAD_SUSPEND**结束状态:**当线程运行结束时将处于关闭状态。关闭状态的线程不参与线程的调度。此状态在RT-thread中的宏定义为RT_THREAD_CLOSE线程优先级RT-Thread最大支持256个线程优先级(0-255),值越小优先级越高。通常Cortex-M采用32个优先级。而普遍的项目中一般10个线程就够用了(面经)时间片每个线程都有时间片但是时间片仅仅对优先级相同的线程有效。[!CAUTION]线程中不能有陷入死循环的操作必须有让出CPU使用权的动作如循环中调用延时函数使线程挂起或者主动挂起线程状态之间的切换[!CAUTION]就绪状态和运行状态是等同的