1. 启动顺序

  1. SystemInit()
  2. $Sub$$main()
  3. rtthread_startup()
  4. rt_application_init()
  5. main_thread_entry
  6. $Super$$main用户主函数

2. 堆范围

自由分配的内存(堆)起始地址为RAM的起始地址加上RW+ZI段后的地址区域。

编译出的program size分为:

  1. Code: 代码段,存放程序的代码部分
  2. RO-data: 只读数据段,存放程序中定义的常量
  3. RW-data: 读写数据段,存放初始化为非0值的全局变量
  4. ZI-data: 0数据段,存放未初始化得全局变量及初始化为0的变量

实际占用空间情况为:

  1. RO Size包含了Code及RO-data,表示程序占用flash空间的大小
  2. RW Size包含了RW-data及ZI-data,表示运行时占用RAM的大小
  3. ROM Size包含了Code, RO Data和RW data,表示烧写程序占用flash空间的大小

板子上电后默认从flash启动,启动之后会将RW段中的RW-data(初始化的全局变量)搬运到RAM中,但不会搬运RO段,即CPU的执行代码从flash中读取,另外根据编译器给出的ZI地址和大小,分配出ZI段,并将这块RAM区域清零。动态内存堆为未使用的RAM空间,应用程序申请和释放的内存都来自该空间

char *ptr;
ptr = rt_malloc(10);
if (ptr != RT_NULL)
{
rt_memset(ptr, 0, 10);
rt_kprintf("malloc success\n");
rt_free(ptr);
ptr = RT_NULL;
}

3. 线程创建

RT-Thread中,线程由三部分组成:线程代码(入口函数)、线程控制块、线程堆栈

3.1 线程代码(入口函数)

无限循环结构
void thread_entry(void *parameter)
{
while(1)
{
/* 等待事件发生 */ /* 处理事件 */
}
} 顺序执行结构
void thread_entry(void *parameter)
{
/* 事务1处理 */
/* 事务2处理 */
/* 事务3处理 */
}

3.2 线程控制块

操作系统管理线程的一个数据结构。存放线程的一些信息,比如优先级、线程名称、线程状态等等,也包括线程与线程之间连接用的链表结构,线程等待时间集合等

struct rt_thread;
struct rt_thread *rt_thread_t;

3.3 线程栈

每个线程都有独立的栈空间,线程切换时,系统会将当前线程的上下文保存在线程栈中,当线程要恢复运行时,再从线程栈中读取上下文信息,恢复线程的运行。线程上下文是指线程执行时的环境,各个变量和数据包括所有的寄存器变量,堆栈信息,内存信息等。线程栈在形式上是一段连续的内存空间,可以通过定义一个数组或者申请一段动态内存来作为线程的栈

创建线程:

创建静态线程
rt_err_t rt_thread_init(struct rt_thread *thread,
const char *name,
void (*entry)(void *parameter),
void *parameter,
void *stack_start,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick) 创建动态线程
rt_thread_t rt_thread_create(const char *name,
void (*entry(void *parameter),
void *parameter,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick)) 启动线程
rt_err_t rt_thread_startup(rt_thread_t thread)
调用此函数后创建的线程会被加入到线程的就绪队列,执行调度 rt_err_t thread_static_init()
{
rt_err_t result; result = rt_thread_init(&thread,
"test",
thread_entry, RT_NULL,
&thread_stack[0], sizeof(thread_stack),
THREAD_PRIORITY, 10); if (result == RT_EOK)
rt_thread_startup(&thread);
else
tc_stat(TC_STAT_END | TC_STAT_FAILED); return result;
} int thread_dynamic_init()
{
rt_thread_t tid; tid = rt_thread_create("test",
thread_entry, RT_NULL,
THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
if (tid != RT_NULL)
rt_thread_startup(tid);
else
tc_stat(TC_STAT_END | TC_STAT_FAILED); return 0;
} rt_thread_delay(15); // 根据时钟频率决定。时钟频率100HZ,那么一次delay 10ms.此处就未150ms
rt_thread_sleep(15);
rt_thread_mdelay(15); // delay 15ms

区别:

  1. 资源分配形式不同:静态线程的线程控制块和线程栈是静态分配的,而动态线程的这两部分是运行时动态分配的
  2. 执行效率:如果堆空间是片外RAM,那么动态线程的运行效率低于静态线程。反之,如果都是片内RAM,则没有差别

4. 系统滴答时钟

心跳时钟由硬件定时器的定时中断产生。称之为系统滴答或者时钟节拍。其频率需要根据CPU的处理能力来决定。始终街拍使得内核可以将线程延时若干个时钟节拍,以及线程等待时间发生时,超时的依据。频率越快,内核函数介入系统运行的概率越大,内核占用的处理器时间就越长,系统的负荷就越大。频率越小,时间处理精度又不够。在stm32平台上一般设置系统滴答频率为100HZ,即每个滴答的时间是10ms。在rtconfig.h中的RT_TICK_PER_SECOND宏,就是代表的HZ数

5. GPIO驱动架构操作IO

#include <rt_device.h>
IO初始化
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
PIN_MODE_OUTPUT
PIN_MODE_INPUT
PIN_MODE_INPUT_PULLUP
PIN_MODE_INPUT_PULLDOWN
PIN_MODE_OUTPUT_OD IO写入
void rt_pin_write(rt_base_t pin, rt_base_t value)
PIN_HIGH
PIN_LOW IO读出
int rt_pin_read(rt_base_t pin) 首先通过看drv_gpio.c中的宏,得知我们设置的芯片有多少个脚。再看__STM32_PIN(2, E, 4).那么这里传入2,就表示要操作PE4引脚

使用msh中的命令:list_thread。列出当前所有线程的栈使用情况



可以先将线程栈大小设置一个固定值(比如2048),在线程运行时通过该命令查看线程栈的使用情况,了解线程栈使用的实际情况,根据情况设置合理的大小。一般将线程栈最大使用量设置为70%

6. 线程优先级 & 时间片

优先级

分别描述了线程竞争处理器资源的能力和持有处理器时间长短的能力。RT-Thread最大支持256个优先级,数值越小优先级越高,0为最高优先级,最低优先级保留给空闲线程idle。可以通过rt_config.h中的RT_THREAD_PRIORITY_MAX宏,修改最大支持的优先级。针对STM32默认设置最大支持32个优先级。具体应用中,线程总数不受限制,能创建的线程总数之和具体硬件平台的内存有关

时间片

只有在相同优先级的就绪态线程中起作用,时间片起到约束线程单次运行时长的作用,其单位是一个系统街拍(OS Tick)

优先级抢占调度

当有高优先级线程处于就绪态后,就会发生任务调度

时间片轮询调度

相同优先级的线程,操作系统按照时间片大小轮流调度线程,时间片起到约束线程单次运行时长的作用。保证同优先级任务轮流占有处理器

7. 钩子函数

空闲线程

特殊的系统线程,具有最低的优先级。系统中无其他就绪线程可运行时,调度器将调度到空闲线程。空闲线程负责一些系统资源回收以及将一些处于关闭态的线程从线程调度列表中移除的动作。空闲线程在形式上是一个无限循环结构,且永远不被挂起。在RT-Thread实时操作系统中空闲线程向用户提供了钩子函数,空闲线程钩子函数可以在系统空闲的时候,执行一些非紧急事务,例如系统运行指示灯闪烁,CPU使用率统计等等

rt_err_t rt_thread_idle_sethook(void(*hook)(void))
rt_err rt_thread_idle_delhook(void(*hook)(void))

注意:

  1. 空闲线程是一个线程状态永远为就绪态的线程,所以钩子函数中执行的相关代码必须保证空闲线程在任何时刻都不会被挂起,例如rt_thread_delay(), rt_sem_take()等可能会导致线程挂起的阻塞类函数,都不能再钩子函数中调用。
  2. 空闲线程可以设置多个钩子函数(有最大限制)

系统调度钩子函数

系统上下文切换是最普遍的时间,如果用户想知道在某一个时刻发生了什么样的线程切换,RT-Thread提供了一个系统调度钩子函数,这个钩子函数在系统进行任务切换时运行,通过这个钩子函数,可以了解到系统任务调度时的信息

rt_scheduler_sethook(void(*hook)(struct rt_thread *from, struct rt_thread *to))

参考文献

  1. RT-Thread视频中心内核入门
  2. RT-Thread文档中心

本文作者: CrazyCatJack

本文链接: https://www.cnblogs.com/CrazyCatJack/p/14408835.html

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

关注博主:如果您觉得该文章对您有帮助,可以点击文章右下角推荐一下,您的支持将成为我最大的动力!


RT-Thread学习笔记1-启动顺序与线程创建的更多相关文章

  1. .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]

    原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...

  2. Spring MVC 学习笔记2 - 利用Spring Tool Suite创建一个web 项目

    Spring MVC 学习笔记2 - 利用Spring Tool Suite创建一个web 项目 Spring Tool Suite 是一个带有全套的Spring相关支持功能的Eclipse插件包. ...

  3. Dubbo -- 系统学习 笔记 -- 快速启动

    Dubbo -- 系统学习 笔记 -- 目录 快速启动 服务提供者 服务消费者 快速启动 Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubb ...

  4. XV6学习笔记(1) : 启动与加载

    XV6学习笔记(1) 1. 启动与加载 首先我们先来分析pc的启动.其实这个都是老生常谈了,但是还是很重要的(也不知道面试官考不考这玩意), 1. 启动的第一件事-bios 首先启动的第一件事就是运行 ...

  5. Boost Thread学习笔记

    thread自然是boost::thread库的主 角,但thread类的实现总体上是比较简单的,前面已经说过,thread只是一个跨平台的线程封装库,其中按照所使用的编译选项的不同,分别决定使用 W ...

  6. MySQL学习笔记——MySQL启动过程(一)

    首先去官网或者github下载MySQL5.7的源码. 官网地址:https://dev.mysql.com/downloads/mysql/ github地址:https://github.com/ ...

  7. apue学习笔记(第十一章 线程)

    本章将进一步深入理解进程,了解如何使用多个控制线程(简单得说就是线程)在单进程环境中执行多个任务. 线程概念 每个线程都包含有表示执行环境所必须的信息:线程ID.一组寄存器值.栈.调度优先级和策略.信 ...

  8. Grunt 学习笔记【2】---- 配置和创建任务

    本文主要讲Grunt任务配置. 说明:本文所有示例都基于Grunt 0.4.5版本. 一 说明 使用Grunt实现项目的打包等工程化工作,实际上是通过Grunt提供的机制和插件,配置一个个任务(例如: ...

  9. Spring框架学习笔记(5)——Spring Boot创建与使用

    Spring Boot可以更为方便地搭建一个Web系统,之后服务器上部署也较为方便 创建Spring boot项目 1. 使用IDEA创建项目 2. 修改groupid和artifact 3. 一路n ...

随机推荐

  1. 转 Fiddler4 手机抓包

    Fiddler4 手机抓包  文章转自:https://www.cnblogs.com/zhengna/p/10876954.html 1.要对计算机Fiddler进行配置,允许远程计算机连接. 2. ...

  2. status 404 reading EduClient#getCourseInfoOrder(String)解决过程

    UcenterClient#getUserInfoOrder(String) failed and no fallback available.解决过程 报错内容: com.netflix.hystr ...

  3. Java并发组件三之Semaphore

    使用场景:常用于使用有限的资源,限制线程并发的最大数量.默认情况下,信号量是非公平性的(先等待先执行为公平.类似于买东西的时候大家排队付款,先来的先付款是公平的.但是这时候有人插队,那就是非公平的)设 ...

  4. Web自动化测试python环境中安装 --selenium安装、火狐和火狐驱动版本、谷歌和谷歌驱动版本、测试

    一.安装selenium Windows命令行(cmd)输入pip install selenium(无须指定版本默认最新)或 pip install selenium==3.141.0(可指定版本) ...

  5. git的使用学习笔记4--创建分支

    1.在git上新建分支 查看本地分支 git branch 查看远程分支 git branch -a 创建一个分支 git checkout -b branch1 再次查看远程分支可以看到该分支 2. ...

  6. Profile Guided Optimization Link Time Optimization

    https://github.com/python/cpython Profile Guided Optimization PGO takes advantage of recent versions ...

  7. Redis 常见问题总结

    1. 简单介绍一下 Redis 呗! 简单来说 Redis 就是一个使用 C 语言开发的数据库,不过与传统数据库不同的是 Redis 的数据是存在内存中的 ,也就是它是内存数据库,所以读写速度非常快, ...

  8. QT串口助手(四):数据发送

    作者:zzssdd2 E-mail:zzssdd2@foxmail.com 一.前言 开发环境:Qt5.12.10 + MinGW 实现的功能 串口数据的发送 ascii字符与hex字符的相互转换 自 ...

  9. P2573 [SCOI2012]滑雪 题解

    下午花了三个小时肝这道题,心态差点爆炸! 下面是分析: 1 题目要求: 2 求最小生成树 3 但是 4 - a是从1号点开始的 --> 如果以后的某个点比一号高,则不可能到达 5 - a只能从高 ...

  10. (五)SpringBoot面试题

    SpringBoot面试题 1.Spring Boot 的自动配置是如何实现的? 2.shiro和oauth还有cas他们之间的关系是什么?问下您公司权限是如何设计,还有就是这几个概念的区别. 2.1 ...