####RT-Thread学习之——静态线程和动态线程
RT-Thread中支持静态和动态两种定义方式。

用线程来举例的话,rt_thread_init对应静态定义方式,rt_thread_create对应动态定义方式。使用静态定义方式时,必须先定义静态的线程控制块,并且定义好堆栈空间,然后调用rt_thread_init来完成线程的初始化工作。采用这种方式,线程控制块和堆栈占用的内存会放在RW段,这段空间在编译时就已经确定,它不是可以动态分配的,所以不能被释放。而只能使用rt_thread_detach函数将该线程控制块从对象管理器中脱离。使用动态定义方式rt_thread_create时,RT-Thread会动态申请线程控制块和堆栈空间。在编译时,编译器是不会感知到这段空间的,只有在程序运行时,RT-Thread才会从系统堆中申请分配这段内存空间,当不需要使用该线程时,调用rt_thread_delete函数就会将这段申请的内存空间重新释放到内存堆中。这两种方式各有利弊,
静态定义方式会占用RW空间,但是不需要动态分配内存,运行时效率高。
动态方式不会占用额外的RW空间,占用空间小,但是运行时需要动态分配内存,效率没有静态方式高。
总的来说,这两种方式就是空间和时间效率的平衡,可以根据实际环境需求选择采用具体的分配方式。

####**线程调度与管理:
1.components.c文件的140行看到#ifdef RT_USING_USER_MAIN宏定义判断,这个宏是定义在rtconfig.h文件内的,而且处于开启状态。同时我们可以在146行看到#if defined (__CC_ARM)的宏定义判断,__CC_ARM就是指keil的交叉编译器名称。
2.除中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占之外,其他部分是可以抢占的,包括线程调度器本身。
3.线程总共支持256个优先级,数值越小优先级越高。
4.线程控制块由结构体struct rt_thread表示
rt_thread_t表示线程的句柄。
5.线程的五种状态:
RT_THREAD_INIT 初始状态
RT_THREAD_READY 就绪状态
RT_THREAD_RUNNIG 运行状态
RT_THREAD_SUSPEND 挂起状态
RT_THREAD_CLOSE 结束状态
6.当系统中无其他线程运行时,调度器将调度到空闲线程。空闲线程通常是一个死循环,永远不会被挂起。

7.调度器相关的接口
(1)调度器初始化   void rt_system_scheduler_init(void);(2)启动调度器       void rt_system_scheduler_start(void);(3)执行调度           void rt_schedule(void);(4)设置调度器钩子  void rt_thread_sethook(void (*hook)(struct rt_thread* from,struct rt_thread* to))  //线程切换时,调度器钩子函数将被调用,用于用户间线程切换void hook(struct rt)_thread* from,struct rt_thread* to);//用于系统间线程切换。8.线程栈空间的大小确定,可以先指定一个稍微大一点的栈空间,再荣国FinSH shell中通过list_thread()命令查看线程运行的过程。9.线程相关接口(1)线程创建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);(2)线程删除rt_err_t rt_thread_delete(rt_thread_t thread);(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);(4)线程脱离  rt_err_t rt_thread_detach (rt_thread_t thread);(5)线程启动 rt_err_t rt_thread_startup(rt_thread_t thread);(6)当前线程rt_thread_t rt_thread_self(void);(7)线程让出处理器rt_err_t rt_thread_yield(void);(8)线程睡眠rt_err_t rt_thread_sleep(rt_tick_t tick);rt_err_t rt_thread_delay(rt_tick_t tick);(9)线程挂起rt_err_t rt_thread_suspend (rt_thread_t thread);(10)线程恢复rt_err_t rt_thread_resume (rt_thread_t thread);(11)线程控制(例如动态更改线程的优先级)rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg);(12)初始化空闲线程void rt_thread_idle_init(void);(13)设置空闲线程钩子void rt_thread_idle_sethook(void (*hook)(void));10.线程设计
RT-Thread中程序运行的上下文包括:
*中断服务例程
*普通线程
*空闲线程

####**定时器管理:

1.软件定时器的最主要目的是:在经过设定的时间后,系统能够自动执行用户设定的动作。当定时器到了,即超时了,执行的动作函数称之为超时函数。2.定时器管理接口:
(1)定时器管理系统初始化。void rt_system_timer_init(void);
(2)创建定时器rt_timer_t rt_timer_create(const char* name,
void (*timeout)(void* parameter), void* parameter,
rt_tick_t time, rt_uint8_t flag);
(3)删除定时器rt_err_t rt_timer_delete(rt_timer_t timer);
(4)初始化定时器void rt_timer_init(rt_timer_t timer,const char* name, void (*timeout)(void* parameter), void* parameter,rt_tick_t time, rt_uint8_t flag);(5)脱离定时器rt_err_t rt_timer_detach(rt_timer_t timer);(6)启动定时器rt_err_t rt_timer_start(rt_timer_t timer);(7)停止定时器rt_err_t rt_timer_stop(rt_timer_t timer);(8)控制定时器rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg);

####**任务间同步通信
核心思想:在访问临界区的时候只允许一个(或者一类)任务运行。

1.关闭中断
关闭中断也叫中断锁,是禁止多任务访问临界区最简单的一种方式。
关闭中断函数:rt_base_t rt_hw_interrupt_disable(void);
恢复中断函数:void rt_hw_interrupt_enable(rt_base_t level);2.调度器锁
与中断锁一样把调度器锁住也能让当前运行的任务不被换出,值到任务调度器解锁。不同之处是对调度器上锁,系统依然能够相应外部中断,中断服务例程依然能进行相应的响应。
调度锁操作API为:
void rt_enter_critical(void); /* 进入临界区*/
void rt_exit_critical(void); /* 退出临界区*/
注: rt_enter_critical/rt_exit_critical可以多次嵌套调用,但每调用一次rt_enter_critical
就必须相对应地调用一次rt_exit_critical退出操作,嵌套的最大深度是65535。3.信号量
信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取和释放它,从而达到同步或者互斥的目的。.信号量相关的函数接口
(1)创建信号量rt_sem_t rt_sem_create (const char* name, rt_uint32_t value, rt_uint8_t flag);
(2)删除信号量rt_err_t rt_sem_delete (rt_sem_t sem);
(3)初始化信号量rt_err_t rt_sem_init (rt_sem_t sem, const char* name, rt_uint32_t value, rt_uint8_t flag);
(4)脱离信号量rt_err_t rt_sem_detach (rt_sem_t sem);
(5)获取信号量rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time);
(6)无等待获取信号量rt_err_t rt_sem_trytake(rt_sem_t sem);
(7)释放信号量rt_err_t rt_sem_release(rt_sem_t sem);
5.互斥量
互斥量又叫相互排斥的信号量,是一种特殊的二值信号量。
互斥量的状态:开锁或闭锁。
(1)创建互斥量rt_mutex_t rt_mutex_create (const char* name, rt_uint8_t flag);
(2)删除互斥量rt_err_t rt_mutex_delete (rt_mutex_t mutex);
(3)初始化互斥量rt_err_t rt_mutex_init (rt_mutex_t mutex, const char* name, rt_uint8_t flag);
(4)脱离互斥量rt_err_t rt_mutex_detach (rt_mutex_t mutex);
(5)获取互斥量rt_err_t rt_mutex_take (rt_mutex_t mutex, rt_int32_t time);
(6)释放信号量rt_err_t rt_mutex_release(rt_mutex_t mutex);
6.事件
事件主要用于线程间的同步,与信号量不同,它的特点是实现一对多,多对多的同步。
RT-Thread定义的事件有以下特点:
*事件只与线程相关,事件间相互独立:每个线程拥有32个事件标志,采用一个32bit无符号整型数进行记录,每一个bit代表一个事件。若干个事件构成一个事件集;
*事件仅用于同步,不提供数据传输功能;
*事件无排队性,即多次向线程发送同一事件(如果线程还未来得及读走),其效果等同于只发送一次。
每个线程都拥有一个事件信息标记,它有三个属性:逻辑与:RT_EVENT_FLAG_END逻辑或:RT_EVENT_FLAG_OR清除标记:RT_EVENT_FLAG_CLEAR
其实关于事件,你可以理解为一系列的标记位,当标记位接收有效,则触发线程中的程序。事件相关接口:
(1)创建线程rt_event_t rt_event_create (const char* name, rt_uint8_t flag);
(2)删除事件rt_err_t rt_event_delete (rt_event_t event);
(3)初始化事件rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag);
(4)脱离事件rt_err_t rt_event_detach(rt_event_t event);
(5)接收事件rt_err_t rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option,
rt_int32_t timeout, rt_uint32_t* recved);
(6)发送事件rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);7.邮箱
邮箱服务是实时操作系统中一种典型的任务间通信方法,特点是开销比较低,效率较
高。
每封邮件只能容纳固定的4个字节内容。
邮箱的相关接口
(1)创建邮箱rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag);
(2)删除邮箱rt_err_t rt_mb_delete (rt_mailbox_t mb);
(3)初始化邮箱rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name, void* msgpool,
rt_size_t size, rt_uint8_t flag)
(4)脱离邮箱rt_err_t rt_mb_detach(rt_mailbox_t mb);
(5)发送邮箱rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value);
(6)等待方式发送邮箱rt_err_t rt_mb_send_wait (rt_mailbox_t mb, rt_uint32_t value, rt_int32_t timeout);
(7)接收邮箱rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout);
8.消息队列
消息队列是另一种常用的线程通讯方式,它能够接收来自线程或中断服务例程中不固定长度的消息。
8.消息队列

消息队列是另一种常用的线程通讯方式,它能够接收来自线程或中断服务例程中不固定长度的消息,并把消息缓存在自己的内存空间中。
消息队列相关接口
(1)创建消息队列
rt_mq_t rt_mq_create(const char* name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag);
(2)删除消息队列
rt_err_t rt_mq_delete(rt_mq_t mq);
(3)初始化消息队列
rt_err_t rt_mq_init(rt_mq_t mq, const char* name, void msgpool, rt_size_t msg_size, rt_size_t pool_size,
rt_uint8_t flag);
(4)脱离消息队列
rt_err_t rt_mq_detach(rt_mq_t mq);
(5)发送消息
rt_err_t rt_mq_send (rt_mq_t mq, void
buffer, rt_size_t size);
(6)发送紧急消息
rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size);
(7)接收消息
rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer, rt_size_t size, rt_int32_t timeout);

内存管理
通常存储空间可以分为两种:内部存储空间和外部存储空间。
RT-Thread操作系统在内存管理上分为:静态分区内存管理与动态内存管理。
动态内存管理又根据内存的多少划分为两种情况:一种是针对小内存块的分配管理(小内存管理算法),另一种是针对大内存块的分配管理(SLAB管理算法)。
静态内存池管理
静态内存池接口
(1)创建内存池
rt_mp_t rt_mp_create(const char* name, rt_size_t block_count, rt_size_t block_size);
(2)删除内存池
rt_err_t rt_mp_delete(rt_mp_t mp);
(3)初始化内存池
rt_err_t rt_mp_init(rt_mp_t mp, const char* name, void *start, rt_size_t size, rt_size_t block size);
(4)脱离内存池
rt_err_t rt_mp_detach(rt_mp_t mp);
(5)分配内存块

F

RT-Thread学习笔记相关推荐

  1. 第98讲:使用SBT开发时动手解决rt.jar中CharSequence is broken等问题学习笔记

    第98讲:使用SBT开发时动手解决rt.jar中CharSequence is broken等问题学习笔记 几乎所有从IDEA官网上下载安装在win上,采用默认方式自动运行的都 会遇到这个问题. er ...

  2. THREAD APC 《寒江独钓》内核学习笔记(4)

    继续学习windows 中和线程有关系的数据结构: ETHREAD.KTHREAD.TEB 1. 相关阅读材料 <windows 内核原理与实现> --- 潘爱民 2. 数据结构分析 我们 ...

  3. [Systemverilog学习笔记] Thread Communication-Event、Semaphore、mailbox

    [Systemverilog学习笔记] Thread Communication-Event.Semaphore.mailbox 学习目标: 通过下文了解Event.Semaphore.mailbox ...

  4. RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的?

    RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 文章目录 RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 前言 项目 ...

  5. MQTT学习笔记——Yeelink MQTT服务 使用mqtt.js和paho-mqtt

    0 前言 2014年8月yeelink推出基于MQTT协议的开关类型设备控制API,相比于基于HTTP RESTful的轮训方式,通过订阅相关主题消息,可以远程控制类应用实时性更好.本文使用两种方式实 ...

  6. DBA高效入职指南学习笔记

    (本文为本人自学oracle,读完DBA高效入职指南一书所记录的学习笔记,仅作为自己日后参考查询使用.) ----------------------------------------------- ...

  7. LwIP学习笔记——STM32 ENC28J60移植与入门

    0.前言 去年(2013年)的整理了LwIP相关代码,并在STM32上"裸奔"成功.一直没有时间深入整理,在这里借博文整理总结.LwIP的移植过程细节很多,博文也不可能一一详解个别 ...

  8. SpringCloud(H版以及Alibaba版本)的学习笔记(三)

    本笔记学习自B站尚硅谷Springcloud时所记录 学习视频链接 源码地址[码云] 笔记内容包括了:Springcloud的H版以及Alibaba版本 H版具体内容包括:Eureka.Zookeep ...

  9. 树莓派学习笔记——yeelink 远程控制LED

    1.前言 前段时间玩了树莓派的GPIO,串口和I2C接口,把树莓派当成单片机来玩,期间深入分析了wiringPi.相对于单片机,以Linux为操作系统的树莓派在网络功能方面要强大的多,下面就结合当下流 ...

  10. Java虚拟机(JVM)与Java内存模型(JMM)学习笔记

    Java虚拟机[JVM]与Java内存模型[JMM]学习笔记 Java虚拟机(JVM) 三种JVM JVM 位置 JVM的主要组成部分及其作用 类加载器 双亲委派机制 沙箱安全机制 Java本地接口( ...

最新文章

  1. 2021年大数据Flink(十六):流批一体API Connectors ​​​​​​​​​​​​​​Redis
  2. 第十六届智能车竞赛比赛进行中 - 参赛队员提出的问题
  3. redis数据类型、应用场景、常用命令
  4. 如何彻底删除SVN中的文件和文件夹(附恢复方法)
  5. Arduino IDE 配置文件
  6. MongoDB 如何使用内存?为什么内存满了?
  7. PyCharm5.0.2最新版破解注册激活码
  8. JSP状态管理 及 Cookie实例
  9. 【原创】关于Git暂存区的理解
  10. Linux阻止SSH暴力***
  11. L1-067 洛希极限 (10 分)
  12. iOS开发之实现方法链调用
  13. Master Reactor Manager Worker TaskWorker(Task)
  14. 多层陶瓷电容器用处_具有综合优异电卡性能的无铅多层陶瓷电容器研究新进展...
  15. Galerkin method 热传导公式推导过程
  16. 【UE4 Plugin】5个必备的蓝图插件,极大提高开发效率
  17. Prometheus+Grafana监控系统
  18. 利用POI将word转换成html实现在线阅读
  19. go每日新闻(2021-08-29)——Go程序内存假泄漏是怎么回事
  20. 百度地图API和高德地图API资料集锦

热门文章

  1. Labwindows/cvi 2017生成软件安装包只能在win10以上系统安装,NI官方给出原因。
  2. 新安江模型Python实现 — — 代码与建模
  3. springboot 网页出现乱码
  4. SpootBoot错误和异常处理机制及错误页指派+全局异常处理
  5. PC-DMIS 2017 基础教程
  6. 仿泰捷视频最新 TV 版
  7. LTE学习:PCFICH信道总结
  8. 基于ssm的课程思政资源众包系统的设计与实现毕业设计源码020838
  9. 37页的《把时间当做朋友》读书笔记PPT
  10. 常用Benchmark