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. 庐山真面目之十一微服务架构手把手教你搭建基于Jenkins的企业级CI/CD环境

    庐山真面目之十一微服务架构手把手教你搭建基于Jenkins的企业级CI/CD环境 一.介绍 说起微服务架构来,有一个环节是少不了的,那就是CI/CD持续集成的环境.当然,搭建CI/CD环境的工具很多, ...

  2. Python爬虫学习笔记(一)

    概念: 使用代码模拟用户,批量发送网络请求,批量获取数据. 分类: 通用爬虫: 通用爬虫是搜索引擎(Baidu.Google.Yahoo等)"抓取系统"的重要组成部分. 主要目的是 ...

  3. TSP旅行商问题

    求解的问题,burma.tsp里面的内容 1 16.47 96.10 2 16.47 94.44 3 20.09 92.54 4 22.39 93.37 5 25.23 97.24 6 22.00 9 ...

  4. fastHttp服务端处理请求的过程

    Github 地址 https://github.com/valyala/fasthttp fastHttp 服务端的处理请求的过程 工作过程 主要代码 设置监听地址 server.go func ( ...

  5. Spring Boot 整合 Freemarker

    Spring Boot 整合 Freemarker 1.Freemarker 简介 2.Spring Boot 整合 Freemarker 2.1 创建工程 2.2 创建类 2.3 其他配置 原文地址 ...

  6. K8s 二、(1、kubeadm部署Kubernetes集群)

    准备工作 满足安装 Docker 项目所需的要求,比如 64 位的 Linux 操作系统.3.10 及以上的内核版本: x86 或者 ARM 架构均可: 机器之间网络互通,这是将来容器之间网络互通的前 ...

  7. svn安装步骤

    我使用的是myeclipse 8.5  svn是site-1.8.22.zip 步骤 1.在myeclipse安装路径下dropins文件夹中创建svn文件夹 2.解压site-1.8.22.zip复 ...

  8. python ---线程,进程,协程

    本章内容 线程 进程 协程 线程是最小的调度单位 进程是最小的管理单元 线程 多线程的特点: 线程的并发是利用cpu上下文切换 多线程的执行的顺序是无序的 多线程共享全局变量 线程是继承在进程里的,没 ...

  9. UML——活动图

    宏观导图 是森马?   活动图,属于UML中动态建模工具图,它描述活动的顺序,展现从一个活动到另一个活动的控制流.活动图着重表现从一个活动到另一个活动的控制流,是内部处理驱动的流程.   其实,说白了 ...

  10. SSL与HTTPS协议

    1.SSL 1.1 什么是SSL SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及 ...