RTT之理解线程

线程与任务等同。

可见,每个线程切换时都会将上下文保存到自己的栈中。线程栈的对齐方式为rtconfig.h中RT_ALIGN_SIZE对齐的RAM空间。

另外从编程手册的timeslice_sample.c这个例子来看,不同的线程调用同一个入口函数,实际上就是将函数的参数及局部变量复制到不同线程的堆栈中,这样就可以实现重入了。

线程控制块结构体rt_thread,也是在rtdef.h中定义。

线程状态转换图:

RTT的就绪态等同于运行态,实际上是不存在运行态的。

线程操作:

创建线程:rt_thread_create动态线程,是从系统自动从内存堆上分配栈空间和线程句柄。(初始化heap之后才能使用)线程创建不可以在中断中调用

rt_thread_init():是用户分配栈空间和线程句柄。可以在中断中调用

注:时间片参数,仅对存在同优先级的线程有效,也就是说同优先级是时间片轮转,对于不同优先级是抢占的形式。

删除线程:rt_thread_delete()对应动态线程删除。rt_thread_detach()对应静态线程删除(由于是静态,所以不能释放对象所占用的内存)。删除不应在本线程内调用。不论动态还是静态删除都可以在中断中调用。

将线程结象移出等待队列、从内核管理器删除、释放申请的堆空间。实际上,用rt_thread_delete函数删除线程接口,仅仅是把相应的线程状态更改为RT_THREAD_CLOSE状态,然后放入到rt_thread_defunct队列中;而真正的删除动作(释放线程控制块和释放线程栈)需要到下一次执行idle线程时,由idle线程完成最后的线程删除动作。

删除可以在中断中调用。

 

启动线程:进入调度序列,并将线程状态改为就绪态。真正的程序运行,是调用调度rt_system_scheduler_start(),启动系统调度器,然后在就绪表中选择一个优先级最高的执行。

可在中断中调用。

 

默认是启动了三个线程,main,tshell,tidel0,下面看一下,这三个线程的优先级分别是多少??

main线程定义在component.c中如下图:

其中RT_THREAD_PRIORITY_MAX是在rtconfig.h中定义的,最大优先级数,默认是32 ,32/3=10,所以main的优先级是10。

tshell线程定义在shell.c中

FINSH_THREAD_PRIORITY,也是定义在rtconfig.h中,默认值是20,可见main线程优先级高于FinSH线程.

最后看一下tidel0线程:

tidel0线程调用是在componet.c中启动函数rtthread_startup(void)中,如下图


定义在系统文件idle.c文件中,是静态创建的一个线程,如下图:

优先级为31级,是最小的。

 

获取当前执行的线程句柄:rt_thread_self(),可以知道是哪个线程在运行。可在中断中调用。

线程让出处理器使用资源:都可以中断中调用。

rt_thread_yield():在就绪表中删除此线程,然后再挂到就绪表的尾部。线程主动让出CPU.选择当前最高优先级线程执行

rt_schedule():切换最高优先级线程。所以当前线程不一定会被换出。

线程睡眠:使线程(主动)挂起指定的时间后,再恢复运行。不可在中断中调用

rt_thread_sleep():

rt_thread_delay():以上两个以系统tick为单位。

rt_thread_mdelay():以时间ms为单位。
线程挂起和恢复:rt_thread_suspend(),挂起,不推荐使用。可以在中断中调用

挂起分为主动:调用上面的线程睡眠API

被动:调用rt_sem_take()或rt_mb_recv()时资源不可使用,导致。

rt_thread_resume():恢复挂起的线程,重新进就绪表
 

控制线程:更改线程的优先级,开启/关闭线程。可以在中断中调用

 

设置调度器钩子函数rt_scheduler_sethook(位于scheduler.c中,安全的,可以在中断中调用)(在系统运行的某一路径一设置一个钩子,当运行到此位置时,转到执行钩子函数,执行完后,再返回正常的路径):在上下文切换时(包括在中断切换),会被调用的函数。

调度器相关的函数:

调度器初始化函数:

 componet.c--->rtthread_startup()---->rt_system_scheduler_init();位于(scheduler.c中)

不安全,不能在中断中调用

调度器启动函数:

componet.c--->rtthread_startup()---->rt_system_scheduler_start();位于(scheduler.c中)

不安全,不能在中断中调用

执行调度:(scheduler.c中)------>   void rt_schedule(void);

安全的,可以在中断中调用

 

空闲线程,最低优先级,是一个死循环,永远不会被挂起。在idel.c中定义。

初始化空闲线程:

componet.c--->rtthread_startup()---->rt_thread_idle_init() 位于idle.c中。

不安全,不可以在中断中调用。

设置和删除空闲钩子函数:

设置rt_thread_idle_sethook:执行空闲函数时要做的事情。钩子函数不能出现挂起操作。不可以在中断中调用。

删除rt_thread_idle_delhook:删除一个空闲线程钩子函数

真正的线程删除操作(rt-thread---->clearup()函数也放到了空闲函数中。

线程设计需要注意的点:

应该非常清楚自己的程序处于何种状态。

程序上下文:包括中断服务例程、普通线程、空闲线程。

空闲线程的钩子函数,可以完成系统运行状态的指示,省电模式等。除此之外,还应1、不会挂起idle线程 2、不应该陷入死循环,需要留出部分时间用于系统处理僵尸线程的系统资源回收。

 

中断服务例程:用的是主堆栈MSP,在这个上下文环境中不能使用挂起当前线程的操作。还应精简短小,是高于任何线程的存在。

 

普通线程:应不可以执行死循环。

 

线程设计要点:

嵌入式实时系统是一种被动系统,被动响应外部事件,当外部事件触发后执行设定的工作内容。需要应注意:

上下文环境:首先思考它的执行环境是什么,工作内容与工作内容间是否有重叠的部分,是否能合并到一起进行处理。

线程的状态跃迁,指线程运行中状态的变化,从就绪态过渡到挂起态。在进行线程设计时,应该保证线程在不活跃的时候,必须让出处理器。这需要明确的知道在什么情况下需要让线程从就绪态跃迁到阻塞态。

线程运行时间长度,线程所关心的一种事件或多种事件触发状态下,线程由阻塞态跃迁为就绪态执行设定的工作,再从就绪态跃迁为阻塞态所需要的时间(一般还应加上这段时间内,这个线程不会被其他线程所抢占的先决条件)。

线程运行时间长度和线程优先级设计密切相关,同时也决定着能否满足实时响应的指标。

 

 

 

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guangod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值