RTT学习之线程管理
获得线程:rt_thread_t rt_thread_self(void);
一 线程的创建和删除:
rt_thread_create()创建的句柄,对应的删除rt_thread_delete(),注意线程的删除只是将线程的状态该为close,进入空闲任务才删除。
rt_thread_init()函数对应的是rt_thread_detach()
二 线程的就绪和挂起:RTT只能是讲一个已经就绪的线程挂起,而不能对已经挂起(调用系统延时函数)的任务再执行挂起操作用suspend!
rt_thread_startup(taskn):使当前线程就绪;
rt_err_t rt_thread_suspend (rt_thread_t thread)使当前线程挂起但很少用,除非在调用该函数后立刻调用rt_schedule()进行调度;
对应的恢复就绪rt_err_t rt_thread_resume (rt_thread_t thread)后也紧跟调用rt_schedule();
yield主动切出挂起;rt_thread_yield()
函数和rt_schedule()
函数的区别:前者从当前线程中切出,插入到本优先级列表尾端,然后转到同优先级的其它线程执行;而后者当前线程不一定切出,只是从调度器重新检查一遍最高优先级就绪任务并执行;
三线程的休眠:
rt_err_t rt_thread_sleep(rt_tick_t tick); rt_err_t rt_thread_delay(rt_tick_t tick);
rt_err_t rt_thread_mdelay(rt_int32_t ms);
四线程控制:rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg);使之就绪、删除、或更改优先级
五空闲线程:
void rt_thread_idle_init(void);
void rt_thread_idle_sethook(void (*hook)(void));
rt_err_t rt_thread_idle_delhook(void (*hook)(void));设置的钩子函数必须保证空闲线程在任何时刻都不会处于挂起状态,主要用于设置状态指示(因不能调用系统延时函数,等待信号所以用处不大,最多只能用条件判断的指示灯)。低功耗模式。删除的线程资源回收。
void rt_scheduler_sethook(void (*hook)(struct rt_thread* from, struct rt_thread* to)调度器钩子用以确定在某个时刻发生了什么线程切换。
六 线程设计:
1 需要知道什么时候让线程进入非就绪态,如果一直就绪,低优先级线程就可能得不到执行的机会。
2 需要确定线程的运行周期、运行时间(task1的响应时间(周期)有要求,则要求其它高优先级任务taskn的执行时间不能超过task1的周期)、优先级的因素
3线程创建步骤:
3.0系统启动流程架构:在rt_application_init()中创建main线程($super$$main必须成对使用,这里是让扩展了Main之后返回到用户main,然后删除自己。硬件初始化,系统初始化,
RT-Thread通过扩展main函数的方式都在component.c里面实现,所以在主main中只有用户自己创建的线程。main线程执行到最后,通过LR寄存器指定的链接地址退出,在
创建main线程的时候,线程栈对应LR寄存器的内容是rt_thread_exit()函数,在
rt_thread_exit里面会把main线程占用的内存空间都释放掉
3.1 创建线程函数,执行什么功能;定义线程堆栈和线程控制块(ID:)
3.2用rt_thread_init()初始化线程任务,任务进入初始化态,调用rt_thread_startup(&led1_thread); 后参与线程调度
#define LED1_StackSize 1024
static rt_uint8_t rt_led1_thread_stack[LED1_StackSize];
static struct rt_thread led1_thread;
rt_thread_init(&led1_thread, /* 线程控制块 */ (1)
"led1", /* 线程名字 */ (2)
led1_thread_entry, /* 线程入口函数 */ (3)
RT_NULL, /* 线程入口函数参数 */ (4)
&rt_led1_thread_stack[0], /* 线程栈起始地址 */ (5)
sizeof(rt_led1_thread_stack), /* 线程栈大小 */ (6)
3, /* 线程的优先级 */ (7)
20); /* 线程时间片,相同优先级才起作用,对只有一个线程时那么该参数不起作用 */
,
线程的栈、控制块用的若静态内存(由编译器负责分配),必须由用户手动预先定义,但这种方法我们在使用RT-Thread的时候用的比较少,通常的方法是在线程创建的时候动态
的分配线程栈和线程控制块的内存空间,即推荐使用动态法创建线程(堆栈大小、优先级、时间片最好宏定义给出增加灵活性)。接下来我们讲解下“创建单线程—SRAM动态内存”的方法(堆),在board.c
static rt_thread_t led1_thread = RT_NULL;
led1_thread = /* 线程控制块指针 */ (1)
rt_thread_create( "led1", /* 线程名字 */ (2)
led1_thread_entry, /* 线程入口函数 */ (3)
512, /* 线程栈大小 不用指定起始地址*/ (5)
3, /* 线程的优先级 */ (6)
20); /* 线程时间片 */ (7)
RT_NULL, /* 线程入口函数参数 */ (4)
if (led1_thread != RT_NULL)
rt_thread_startup(led1_thread); /* 启动线程,开启调度 */
else
return -1;
线程的管理:
RT-Thread内核中采用了基于位图的优先级算法(时间复杂度O(1),即与就绪线程的多少无关)。
在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自身。
时间片轮转调度仅在当前系统中无更高优先级就绪线程存在的情况下才有效,也可以是一个任务的2个副本。