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. JVM(四)打破双亲委派和SPI机制

    前言: 我们都知道判断两个类是不是同一个,要根据类加载器和全限定名.这是为什么呢?为什么不同的类加载器加载同一个类是不同的呢? 答案就是,不同的类加载器所加载的类在方法区的存储空间是不同的即Insta ...

  2. Jmeter-插件扩展及性能监控插件的安装

    需要对http服务进行大数据量的传值测试:看看产品中的http服务,能支持传多少字符:目标值是希望能到10w+: 上次测试中,服务器总是内存满导致服务不响应,因此想增加对服务端的性能监控:查阅了smi ...

  3. Python PyCharm安装第三方库

    第一步:在PyCharm菜单中选择File--->Settings 第二步:在设置页出现的搜索框搜索:Project Interpreter 或者直接定位到此处 第三步:输入库名,搜索安装第三方 ...

  4. python3编码转换

    str->bytes:encode编码 bytes->str:decode解码 字符串通过编码成为字节码,字节码通过解码成为字符串. >>> text = '我是文本' ...

  5. JAVA中两个int类型的变量在不借助第三个变量的情况下完成值的互换

    在面试中被问到这个问题,想到两种解决方式,在此分享一下. 第一种,使用简单的数学运算达到目标(但是面试官往往会问你还有没有其他方式): public static void main(String[] ...

  6. 3D运动类申明与实现

    #ifndef PKM3D_H #define PKM3D_H #include"kinematics.h" #include"Inventor/Qt/viewers/S ...

  7. IDEA中jdk设置

    电脑运行环境是8, 但是IDEA提醒说1.5已经过时,IDEA中jdk设置还是比较麻烦 https://blog.csdn.net/u012365843/article/details/8138883 ...

  8. 【十天自制软渲染器】DAY 03:画一个三角形(向量叉乘算法 & 重心坐标算法)

    如果你喜欢我写的文章,可以把我的公众号设为星标 ,这样每次有更新就可以及时推送给你啦. 前面两天画了点和线,今天我们来画一个最简单也是最强大的面--三角形. 本文主要讲解三角形绘制算法的推导和思路(只 ...

  9. python--基础2 (数据类型及应用)

    资源池 链接:https://pan.baidu.com/s/1OGq0GaVcAuYEk4F71v0RWw 提取码:h2sd python数据类型 字符串 列表 字典 数字(整数) 数字(浮点数) ...

  10. poj 3278 Catch That Cow(记忆化广度优先搜索)

    题意: 0到N的数轴上,每次可以选择移动到x-1,x+1,2*x,问从n移动到k的最少步数. 思路: 同时遍历三种可能并记忆化入队即可. Tips: n大于等于k时最短步数为n-k. 在移动的过程中可 ...