STM32之RTOS移植和使用
1. RT-Thread概述
RT - Thread(Real - Time - Thread)是一个开源、成熟、可商用的嵌入式实时操作系统。它由中国开源社区主导开发,并得到了来自全球开发者的贡献。RT - Thread 不仅仅是一个实时内核,它也是一个完整的组件平台,包含了文件系统、网络框架、设备框架等,适用于各种资源受限的微控制器(MCU)和物联网(IoT)应用。
RT - Thread 官网
-
开源免费:遵循 Apache License 2.0 协议,可以免费用于商业产品,无需担心版权问题。
-
可裁剪性:采用高度模块化的设计,允许开发者根据项目需求,像搭积木一样对系统功能进行裁剪和配置,最小内核仅需 1.2KB ROM 和 1KB RAM。
-
丰富的组件:提供了被称为 “软件包” 的庞大生态系统,包含近 500 个可选的、开箱即用的软件组件(如网络协议栈、文件系统、GUI、音频框架、云连接套件等),极大地加速了产品开发。
-
跨平台与多架构支持:支持所有主流 CPU 架构,如 ARM(Cortex - M/R/A)、RISC - V、MIPS、Xtensa 等。同时,其开发工具(Env,Scons)和模拟器可以在 Windows、Linux、macOS 上运行。
-
良好的开发体验:提供了强大的构建工具(scons + env)和易于使用的配置工具(menuconfig),使得配置和构建系统变得非常简单。同时,与主流 IDE(如 Keil MDK,IAR,RT - Thread Studio)集成良好。
-
活跃的社区:拥有庞大且活跃的中文社区,文档、教程和问题解答资源非常丰富,降低了学习和开发的门槛。
-
内核层:
- 核心内核:提供实时操作系统的基本功能,包括多任务调度(线程)、同步机制(信号量、互斥锁、事件集)、进程间通信(邮箱、消息队列)、内存管理(静态内存池、动态堆内存管理)、定时器等。
- 设备驱动框架(I/O Device Framework):提供了一套标准的设备驱动接口(如 open,close,read,write,control),将应用和底层硬件(如 UART,SPI,I2C,ADC)隔离开来,实现了驱动的标准化和可复用性。
-
组件层:
- 这是在内核之上的一系列可选的系统级服务,例如:
- 虚拟文件系统(VFS):为上层提供统一的文件操作接口,下层可以对接多种具体文件系统(如 FATFS,LittleFS,ROMFS 等)。
- 网络框架:包含轻量级的 TCP/IP 协议栈(lwIP)以及丰富的网络软件包(如 MQTT,HTTP,WebSocket,TLS 等),方便开发物联网应用。
- 其他高级功能:如命令外壳(FinSH)、图形用户界面(GUI)、脚本引擎(MicroPython,JavaScript)等。
- 这是在内核之上的一系列可选的系统级服务,例如:
-
软件包层:
- 这是 RT - Thread 生态系统的核心优势。它是一个由社区维护的、面向物联网应用领域的开源软件仓库。开发者可以通过 RT - Thread 的包管理工具一键式地将需要的功能(如传感器驱动、算法库、云平台 SDK)添加到自己的项目中,实现 “搭积木” 式的开发。
2. 实时操作系统
- 轮询:程序按照最基本的顺序结构,从上至下执行。同时利用循环结构,例如 while 循环控制目标程序的重复执行,重复操作。
- 前后台:在程序执行过程中,轮询过程中,程序触发【中断】,内部中断和外部中断。
- 前台,当前中断触发,中断处理函数就成为当前程序【前台】。
- 后台,被中断处理函数压栈的功能代码。
- 时间片:
- 基于当前 STM32F103ZET6 芯片,芯片执行一次任务 / 操作的时间是 13.888ns,可以认为单一执行操作的时间就是当前芯片的时间片。
- 可以利用时间片操作,将 MCU 执行任务进行线程调度,从而实现多线程任务执行。
- 实时操作系统核心,多任务,多线程,线程通信,任务调度
对比维度 | 实时操作系统(RTOS) | Linux 操作系统 |
---|---|---|
核心设计目标 | 保障任务严格实时响应,追求 “确定性”,确保高优先级任务在规定时间内执行 | 兼顾多任务并发、资源公平分配,注重系统整体吞吐量、通用性与用户体验 |
实时性类型 | 支持硬实时(严格时间约束,超时会引发严重后果,如工业控制 )和软实时(尽量快速响应,允许一定延迟,如部分嵌入式交互 ) | 经实时补丁(如 PREEMPT_RT )优化可实现软实时,但原生设计难满足硬实时严格要求 |
内核架构 | 多为微内核或可高度裁剪的内核,仅保留任务调度、基础内存管理、中断处理等核心功能,体积小巧 | 宏内核架构,集成进程管理、虚拟内存、复杂文件系统、完备网络协议栈等庞大功能,内核代码量大 |
资源占用 | 极度精简,最小内核可至几 KB 级别,适配 MCU 等资源受限设备(如物联网传感器节点 ) | 对资源需求高,运行需几十 MB 以上内存,依赖相对充足的 CPU 算力、存储资源 |
任务调度 | 采用优先级抢占调度、时间片轮转调度等,优先保障高优先级任务快速执行,调度延迟可精准控制 | 基于 CFS(完全公平调度 )等通用调度算法,追求多任务公平性,高负载下难保证极低调度延迟 |
应用场景 | 聚焦对实时性、可靠性要求严苛的嵌入式场景,如工业自动化控制(产线设备、机器人 )、汽车电子(发动机控制、安全系统 )、航空航天(飞行控制 )、医疗设备(监护仪、手术机器人 ) | 覆盖通用计算场景,从服务器(云计算、大数据 )、桌面办公(日常软件使用 )到高端嵌入式(智能汽车中控、智能设备网关 ),强调功能丰富与兼容性 |
3. RT-Thread Nano 版移植

3.1 移植源码内容
3.2 Keil 项目配置

4. RTT 多线程
4.1 RTT 线程状态
4.2 多线相关 API
4.2.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);
参数说明:
name
:线程的名称,是一个以\0
结尾的字符串。entry
:线程入口函数指针,该函数是线程实际执行的代码。parameter
:传递给线程入口函数的参数。stack_size
:线程栈的大小,单位为字节。priority
:线程的优先级,数值越小优先级越高。tick
:线程的时间片大小,即线程每次获得 CPU 执行的最大时间刻度。
返回值:
- 成功创建时返回线程句柄(线程控制块指针);失败时返回
RT_NULL
。
4.2.2 线程初始化
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);
参数说明:
thread
:线程控制块指针,需要用户预先定义。- 其他参数与
rt_thread_create
类似。
返回值:
- 成功时返回
RT_EOK
;失败时返回错误码。
对比维度 | rt_thread_create | rt_thread_init |
---|---|---|
内存分配方式 | 动态内存分配:线程控制块和栈空间由系统从堆中自动分配。 | 静态内存分配:线程控制块和栈空间需用户预先定义(如全局变量或静态变量)。 |
函数返回值 | 返回线程句柄(rt_thread_t 类型),失败返回 RT_NULL 。 | 返回错误码(rt_err_t 类型),成功返回 RT_EOK 。 |
线程删除方式 | 使用 rt_thread_delete() 释放线程资源(自动回收堆内存)。 | 使用 rt_thread_detach() 脱离线程(不自动释放内存,需用户手动管理)。 |
适用场景 | 适合内存资源相对充足、需要动态创建 / 销毁线程的场景(如临时任务)。 | 适合内存受限、对确定性要求高的场景(如资源固定的嵌入式设备),可避免动态内存碎片。 |
用户操作复杂度 | 无需手动管理内存,使用简单,但可能产生内存碎片。 | 需要手动定义线程控制块和栈,操作稍复杂,但内存分配更可控。 |
4.2.3 线程启动
rt_err_t rt_thread_startup(rt_thread_t thread);
参数说明:
thread
:线程句柄,即rt_thread_create
或rt_thread_init
返回的线程控制块指针。
返回值:
- 成功时返回
RT_EOK
;失败时返回错误码。
4.2.4 线程删除
rt_err_t rt_thread_delete(rt_thread_t thread);
参数说明:
thread
:线程句柄,由rt_thread_create
创建的线程才能使用此函数删除。
返回值:
- 成功时返回
RT_EOK
;失败时返回错误码。
4.2.5 线程脱离
rt_err_t rt_thread_detach(rt_thread_t thread);
参数说明:
thread
:线程句柄,由rt_thread_init
初始化的线程才能使用此函数脱离。
返回值:
- 成功时返回
RT_EOK
;失败时返回错误码。
4.2.6 线程挂起
rt_err_t rt_thread_suspend(rt_thread_t thread);
参数说明:
thread
:线程句柄。
返回值:
- 成功时返回
RT_EOK
;失败时返回错误码。
4.2.7 线程恢复
rt_err_t rt_thread_resume(rt_thread_t thread);
参数说明:
thread
:线程句柄。
返回值:
- 成功时返回
RT_EOK
;失败时返回错误码。
4.2.8 线程让出 CPU
void rt_thread_yield(void);
功能:
- 当前线程主动让出 CPU,让同优先级或更高优先级的线程有机会执行。
4.2.9 线程睡眠
rt_err_t rt_thread_sleep(rt_tick_t tick);
参数说明:
tick
:线程睡眠的时间,单位为系统时钟节拍。
返回值:
- 成功时返回
RT_EOK
;失败时返回错误码。
4.3 多线程调度问题

4.4 Mutex 互斥锁/互斥量
4.4.1 创建互斥锁
rt_mutex_t rt_mutex_create(const char *name,rt_uint8_t flag);
- 功能:动态创建一个互斥锁对象。
- 参数:
name
:互斥锁的名称,用于在系统中标识该互斥锁,方便调试和管理。flag
:互斥锁的标志,目前 RT-Thread 中互斥锁只有一种标志RT_IPC_FLAG_FIFO
,表示采用先进先出(FIFO)的线程等待唤醒算法。
- 返回值:
- 若创建成功,返回互斥锁的句柄(
rt_mutex_t
类型)。 - 若创建失败,返回
RT_NULL
。
- 若创建成功,返回互斥锁的句柄(
4.4.2 删除互斥锁
rt_err_t rt_mutex_delete(rt_mutex_t mutex);
- 功能:删除一个动态创建的互斥锁对象,释放其占用的系统资源。
- 参数:
mutex
:要删除的互斥锁的句柄。
- 返回值:
RT_EOK
:表示互斥锁删除成功。- 其他错误码:表示删除过程中出现错误。
4.4.3 初始化静态互斥锁
rt_err_t rt_mutex_init(rt_mutex_t mutex,const char *name,rt_uint8_t flag);
- 功能:初始化一个预先定义的静态互斥锁对象。
- 参数:
mutex
:预先定义的静态互斥锁对象的指针。name
:互斥锁的名称。flag
:互斥锁的标志,通常为RT_IPC_FLAG_FIFO
。
- 返回值:
RT_EOK
:表示互斥锁初始化成功。- 其他错误码:表示初始化过程中出现错误。
4.4.4 获取互斥锁
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time);
- 功能:获取指定的互斥锁。如果互斥锁当前未被其他线程持有,则调用线程可以立即获取该互斥锁;如果互斥锁已被其他线程持有,则调用线程根据
time
参数的设置进行相应的处理。 - 参数:
mutex
:要获取的互斥锁的句柄。time
:等待获取互斥锁的超时时间,单位为系统时钟节拍,取值情况如下:RT_WAITING_FOREVER
:表示线程会一直等待,直到获取到互斥锁。0
:表示线程不会等待,若互斥锁不可用,立即返回。- 正整数:表示线程最多等待指定的时钟节拍数,若在该时间内未获取到互斥锁,则返回错误。
- 返回值:
RT_EOK
:表示成功获取到互斥锁。RT_ETIMEOUT
:表示等待超时,未能获取到互斥锁。- 其他错误码:表示出现其他错误。
4.4.5 释放互斥锁
rt_err_t rt_mutex_release(rt_mutex_t mutex);
- 功能:释放指定的互斥锁,允许其他线程获取该互斥锁。
- 参数:
mutex
:要释放的互斥锁的句柄。
- 返回值:
RT_EOK
:表示互斥锁释放成功。- 其他错误码:表示释放过程中出现错误。
4.5 Semaphore 信号量
信号量操作类似于 Mutex 互斥锁,也可以通过信号量进行线程同步与顺序控制。
4.5.1 创建信号量
rt_sem_t rt_sem_create(const char *name,rt_int32_t value,rt_uint8_t flag);
- 功能:动态创建一个信号量对象。
- 参数:
name
:信号量的名称,用于在系统中标识该信号量,方便调试和管理。value
:信号量的初始值,它代表了可用资源的数量。flag
:信号量的标志,目前有RT_IPC_FLAG_FIFO
(先进先出调度算法)和RT_IPC_FLAG_PRIO
(优先级调度算法)。
- 返回值:
- 若创建成功,返回信号量的句柄(
rt_sem_t
类型)。 - 若创建失败,返回
RT_NULL
。
- 若创建成功,返回信号量的句柄(
4.5.2 删除信号量
rt_err_t rt_sem_delete(rt_sem_t sem);
- 功能:删除一个动态创建的信号量对象,释放其占用的系统资源。
- 参数:
sem
:要删除的信号量的句柄。
- 返回值:
RT_EOK
:表示信号量删除成功。- 其他错误码:表示删除过程中出现错误。
4.5.3 初始化静态信号量
rt_err_t rt_sem_init(rt_sem_t sem,const char *name,rt_int32_t value,rt_uint8_t flag);
- 功能:初始化一个预先定义的静态信号量对象。
- 参数:
sem
:预先定义的静态信号量对象的指针。name
:信号量的名称。value
:信号量的初始值。flag
:信号量的标志,如RT_IPC_FLAG_FIFO
或RT_IPC_FLAG_PRIO
。
- 返回值:
RT_EOK
:表示信号量初始化成功。- 其他错误码:表示初始化过程中出现错误。
4.5.4 脱离静态信号量
rt_err_t rt_sem_detach(rt_sem_t sem);
- 功能:将一个静态初始化的信号量从系统中脱离,释放相关资源。
- 参数:
sem
:要脱离的静态信号量对象的指针。
- 返回值:
RT_EOK
:表示信号量脱离成功。- 其他错误码:表示脱离过程中出现错误。
4.5.5 获取信号量
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time);
- 功能:获取指定的信号量。如果信号量的当前值大于 0,则将信号量的值减 1,并立即返回;如果信号量的值为 0,调用线程会根据
time
参数的设置进行相应的处理。 - 参数:
sem
:要获取的信号量的句柄。time
:等待获取信号量的超时时间,单位为系统时钟节拍,取值情况如下:RT_WAITING_FOREVER
:表示线程会一直等待,直到获取到信号量。0
:表示线程不会等待,若信号量不可用,立即返回。- 正整数:表示线程最多等待指定的时钟节拍数,若在该时间内未获取到信号量,则返回错误。
- 返回值:
RT_EOK
:表示成功获取到信号量。RT_ETIMEOUT
:表示等待超时,未获取到信号量。- 其他错误码:表示出现其他错误。
4.5.6 释放信号量
rt_err_t rt_sem_release(rt_sem_t sem);
- 功能:释放指定的信号量,将信号量的值加 1,如果有线程正在等待该信号量,会唤醒其中一个线程。
- 参数:
sem
:要释放的信号量的句柄。
- 返回值:
RT_EOK
:表示信号量释放成功。- 其他错误码:表示释放过程中出现错误。
4.6 Message Queue(消息队列)
在 RT-Thread 实时操作系统中,消息队列是一种常用的线程间通信方式。它允许一个或多个线程向消息队列发送消息,也允许一个或多个线程从消息队列中接收消息。以下是 RT-Thread 消息队列与消息队列相关的 API 及其详细介绍。
4.6.1 创建消息队列
rt_mq_t rt_mq_create(const char *name,rt_size_t msg_size,rt_size_t max_msgs,rt_uint8_t flag);
- 功能:创建一个新的消息队列对象。
- 参数:
name
:消息队列的名称。msg_size
:每条消息的最大长度(以字节为单位)。max_msgs
:消息队列中允许存储的最大消息数量。flag
:消息队列的创建标志,例如RT_IPC_FLAG_FIFO
(先进先出)或RT_IPC_FLAG_PRIO
(按优先级)。
- 返回值:
- 成功:返回消息队列对象的句柄(
rt_mq_t
类型)。 - 失败:返回
RT_NULL
。
- 成功:返回消息队列对象的句柄(
4.6.2 删除消息队列
rt_err_t rt_mq_delete(rt_mq_t mq);
- 功能:删除一个已创建的消息队列对象。
- 参数:
mq
:要删除的消息队列对象的句柄。
- 返回值:
RT_EOK
:删除成功。- 其他错误码:删除失败。
4.6.3 发送消息到消息队列
rt_err_t rt_mq_send(rt_mq_t mq, const void *buffer, rt_size_t size);
- 功能:将一条消息发送到指定的消息队列中。
- 参数:
mq
:目标消息队列对象的句柄。buffer
:指向要发送的消息数据的指针。size
:要发送的消息的长度(不超过msg_size
)。
- 返回值:
RT_EOK
:发送成功。RT_ETIMEOUT
:消息队列已满,发送超时。- 其他错误码:发送失败。
4.6.4 无等待发送消息到消息队列
rt_err_t rt_mq_urgent(rt_mq_t mq, const void *buffer, rt_size_t size);
- 功能:将一条消息紧急发送到指定的消息队列头部,不进行等待。
- 参数:
mq
:目标消息队列对象的句柄。buffer
:指向要发送的消息数据的指针。size
:要发送的消息的长度(不超过msg_size
)。
- 返回值:
RT_EOK
:发送成功。RT_ETIMEOUT
:消息队列已满,发送超时。- 其他错误码:发送失败。
-
函数 入队逻辑核心差异 通俗理解 rt_mq_send
消息会被放到消息队列的尾部,遵循 “先进先出(FIFO)” 顺序 普通排队,新来的消息排到队尾,等前面消息处理完才会被处理 rt_mq_urgent
消息会被插入到消息队列的头部,遵循 “后进先出(LIFO)” 逻辑(仅针对紧急消息场景 ) 紧急插队,新来的紧急消息直接放队首,能被优先处理
4.6.5 从消息队列接收消息
rt_err_t rt_mq_recv(rt_mq_t mq,void *buffer,rt_size_t size,rt_int32_t timeout);
- 功能:从指定的消息队列中接收一条消息。
- 参数:
mq
:目标消息队列对象的句柄。buffer
:用于存储接收到的消息数据的缓冲区指针。size
:缓冲区的大小(应不小于msg_size
)。timeout
:等待消息的超时时间(以时钟节拍为单位),RT_WAITING_FOREVER
表示永久等待。
- 返回值:
RT_EOK
:接收成功。RT_ETIMEOUT
:等待超时,未接收到消息。- 其他错误码:接收失败。
5. RTT 定时器
在 RT-Thread(RTT)实时操作系统中,定时器(Timer)是一种常用的系统组件,可用于在特定的时间点触发函数周期性执行。下面详细介绍 RT 定时器的相关内容,包括基本概念、API 函数说明等。
基本概念
- 单次触发定时器:定时器启动后,在指定的时间点触发一次回调函数,之后定时器自动停止。
- 周期触发定时器:定时器启动后,会按照设定的时间周期重复触发回调函数,直到被手动停止或删除。
- 定时器的时间单位:基于 RT-Thread 的系统时钟节拍(tick),需结合系统时钟配置理解实际时间。
5.1 RT 定时器 API
5.1.1 创建定时器
rt_timer_t rt_timer_create(const char *name,void (*timeout)(void *parameter),void *parameter,rt_tick_t time,rt_uint8_t flag);
参数:
name
:定时器的名称,用于在系统中标识定时器,方便调试和管理。timeout
:定时器的超时回调函数,定时器触发时执行该函数。parameter
:传递给超时回调函数的参数。time
:定时器的超时时间,以系统时钟节拍为单位。flag
:定时器的标志,取值说明如下:RT_TIMER_FLAG_ONE_SHOT
:单次触发定时器。RT_TIMER_FLAG_PERIODIC
:周期触发定时器。RT_TIMER_FLAG_HARD_TIMER
:硬件定时器(需硬件支持)。RT_TIMER_FLAG_SOFT_TIMER
:软件定时器。
-
对比项 RT_TIMER_FLAG_HARD_TIMER
(硬件定时器)RT_TIMER_FLAG_SOFT_TIMER
(软件定时器)实现依赖 依赖硬件定时器资源(如芯片的定时 / 计数器外设 ) 基于系统 Tick 构建,依托软件模拟实现 执行上下文 中断上下文(触发时直接在中断里执行回调 ) 线程上下文(定时器线程中执行回调 ) 精度与实时性 精度高(纳秒级,由硬件决定 )、实时性强,触发不依赖系统调度 精度略低(受系统 Tick 影响,毫秒级或更粗 )、实时性弱,需等待线程调度 资源限制 数量有限(受硬件定时器外设数量制约,如 STM32 某系列可能只有 4 个 ) 数量无严格限制(理论上只要内存足够,可创建大量软件定时器 ) 回调函数要求 必须极简、“中断安全”(不能阻塞、不能调用非中断安全的 RT-Thread API ) 可执行复杂逻辑(允许阻塞、调用常规 RT-Thread API )
返回值:
- 成功创建:返回定时器的句柄(
rt_timer_t
类型 )。 - 创建失败:返回
RT_NULL
。
5.1.2 启动定时器
rt_err_t rt_timer_start(rt_timer_t timer);
参数:
timer
:要启动的定时器句柄。
返回值:
RT_EOK
:表示定时器启动成功。- 其他错误码:表示定时器启动过程中出现错误。
5.1.3 停止定时器
rt_err_t rt_timer_stop(rt_timer_t timer);
参数:
timer
:要停止的定时器句柄。
返回值:
RT_EOK
:表示定时器停止成功。- 其他错误码:表示定时器停止过程中出现错误。
5.1.4 重新启动定时器
rt_err_t rt_timer_restart(rt_timer_t timer);
参数:
timer
:要重新启动的定时器句柄。
返回值:
RT_EOK
:表示定时器重新启动成功。- 其他错误码:表示定时器重新启动过程中出现错误。
5.1.5 初始化静态定时器
rt_err_t rt_timer_init(rt_timer_t timer,const char *name,void (*timeout)(void *parameter),void *parameter,rt_tick_t time,rt_uint8_t flag);
参数:
timer
:预先定义的静态定时器对象的指针。name
:定时器的名称。timeout
:定时器的超时回调函数。parameter
:传递给超时回调函数的参数。time
:定时器的超时时间,以系统时钟节拍为单位。flag
:定时器的标志,同rt_timer_create
中的flag
取值(如RT_TIMER_FLAG_ONE_SHOT
、RT_TIMER_FLAG_PERIODIC
等 )。
返回值:
RT_EOK
:表示定时器初始化成功。- 其他错误码:表示定时器初始化过程中出现错误。
5.1.6 销毁定时器
rt_err_t rt_timer_detach(rt_timer_t timer);
参数:
timer
:要销毁的定时器句柄(由rt_timer_init
初始化的静态定时器适用 )。
返回值:
RT_EOK
:表示定时器销毁成功。- 其他错误码:表示定时器销毁过程中出现错误。
6. RT-Thread Hook 组件
6.1 Hook 核心特性
- 非侵入性:无需修改内核代码,通过 API 注册即可扩展功能。
- 事件驱动:仅在对应内核事件(如线程挂起、定时器超时)触发时执行,不影响系统正常流程。
- 轻量化:每个 Hook 类型仅支持注册一个回调函数(避免多回调带来的性能开销),后续注册会覆盖之前的回调。
- 依赖配置:需在
rtconfig.h
中开启RT_USING_HOOK
宏(#define RT_USING_HOOK
),否则 Hook 相关 API 会被编译忽略。
6.2 Hook 相关 API
6.2.1 线程 Hook(Thread Hook)
用于监控线程的初始化、挂起、恢复三类核心事件,可用于跟踪线程生命周期状态。
6.2.1.1 设置线程初始化 Hook
void rt_thread_inited_sethook(void (*hook)(rt_thread_t thread));
- 功能:注册线程初始化回调函数,当通过
rt_thread_init
或rt_thread_create
完成线程初始化时,自动触发该 Hook。 - 参数:
hook
为用户实现的回调函数指针,函数原型为void (*)(rt_thread_t thread)
,其中thread
为当前完成初始化的线程句柄。 - 返回值:无。
6.2.1.2 设置线程挂起 Hook
void rt_thread_suspend_sethook(void (*hook)(rt_thread_t thread));
- 功能:注册线程挂起回调函数,当通过
rt_thread_suspend
成功挂起线程时,自动触发该 Hook。 - 参数:
hook
为用户实现的回调函数指针,函数原型为void (*)(rt_thread_t thread)
,其中thread
为被挂起的线程句柄。 - 返回值:无。
6.2.1.3 设置线程恢复 Hook
void rt_thread_resume_sethook(void (*hook)(rt_thread_t thread));
- 功能:注册线程恢复回调函数,当通过
rt_thread_resume
成功恢复线程时,自动触发该 Hook。 - 参数:
hook
为用户实现的回调函数指针,函数原型为void (*)(rt_thread_t thread)
,其中thread
为被恢复的线程句柄。 - 返回值:无。
6.2.2 调度器 Hook(Scheduler Hook)
用于监控线程切换事件,可跟踪系统中线程调度的路径和频率,常用于性能分析。
void rt_scheduler_sethook(void (*hook)(rt_thread_t from, rt_thread_t to));
- 功能:注册线程调度切换回调函数,当内核完成线程上下文切换(从一个线程切换到另一个线程)前,自动触发该 Hook。
- 参数:
hook
为用户实现的回调函数指针,函数原型为void (*)(rt_thread_t from, rt_thread_t to)
,其中from
为切换前正在运行的线程句柄(若为RT_NULL
,表示系统首次调度 );to
为切换后即将运行的线程句柄。 - 返回值:无。
6.2.3 定时器 Hook(Timer Hook)
用于监控定时器超时事件,在定时器回调函数执行前触发,可用于定时器执行日志记录或预处理。
void rt_timer_timeout_sethook(void (*hook)(struct rt_timer *timer));
- 功能:注册定时器超时回调函数,当定时器达到设定的超时时间后,在执行用户定义的定时器回调函数(
timeout
)前,自动触发该 Hook。 - 参数:
hook
为用户实现的回调函数指针,函数原型为void (*)(struct rt_timer *timer)
,其中timer
为当前超时的定时器句柄(可通过timer->parent.name
获取定时器名称 )。 - 返回值:无。
6.2.4 内存 Hook(Memory Hook)
用于监控动态内存分配 / 释放事件,可跟踪内存使用情况、检测内存泄漏或野指针问题。
6.2.4.1 设置内存分配 Hook
void rt_malloc_sethook(void (*hook)(void *ptr, rt_uint32_t size));
- 功能:注册内存分配回调函数,当通过
rt_malloc
或rt_calloc
成功分配内存后,自动触发该 Hook。 - 参数:
hook
为用户实现的回调函数指针,函数原型为void (*)(void *ptr, rt_uint32_t size)
,其中ptr
为分配成功的内存块首地址 ;size
为分配的内存块大小(单位:字节 )。 - 返回值:无。
6.2.4.2 设置内存释放 Hook
void rt_free_sethook(void (*hook)(void *ptr));
- 功能:注册内存释放回调函数,当通过
rt_free
释放内存块前,自动触发该 Hook。 - 参数:
hook
为用户实现的回调函数指针,函数原型为void (*)(void *ptr)
,其中ptr
为即将释放的内存块首地址 。 - 返回值:无。
6.2.5 中断 Hook(Interrupt Hook)
用于监控中断进入 / 退出事件,可统计中断触发频率、嵌套层数,或实现中断相关的日志记录。
6.2.5.1 设置中断进入 Hook
void rt_interrupt_enter_sethook(void (*hook)(void));
- 功能:注册中断进入回调函数,当系统进入中断服务程序(执行
rt_interrupt_enter
后),自动触发该 Hook。 - 参数:
hook
为用户实现的回调函数指针,函数原型为void (*)(void)
(无参数,可通过rt_interrupt_get_nest()
获取当前中断嵌套层数 )。 - 返回值:无。
6.2.5.2 设置中断退出 Hook
void rt_interrupt_leave_sethook(void (*hook)(void));
- 功能:注册中断退出回调函数,当系统退出中断服务程序(执行
rt_interrupt_leave
前),自动触发该 Hook。 - 参数:
hook
为用户实现的回调函数指针,函数原型为void (*)(void)
(无参数,可通过rt_interrupt_get_nest()
获取当前中断嵌套层数 )。 - 返回值:无。
7. 具体代码示例
#include <rtthread.h>#define THREAD_PRIORITY 8
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5// 共享资源和互斥锁
static rt_uint32_t shared_counter = 0;
static rt_mutex_t mutex = RT_NULL;// 定时器句柄
static rt_timer_t timer = RT_NULL;// 1. 线程Hook回调函数
static void thread_suspend_hook(rt_thread_t thread)
{rt_kprintf("[Hook] Thread suspended: %s\n", thread->name);
}static void thread_resume_hook(rt_thread_t thread)
{rt_kprintf("[Hook] Thread resumed: %s\n", thread->name);
}static void thread_inited_hook(rt_thread_t thread)
{rt_kprintf("[Hook] Thread initialized: %s (pri: %d)\n", thread->name, thread->current_priority);
}// 2. 调度器Hook回调函数
static void scheduler_hook(rt_thread_t from, rt_thread_t to)
{if (from)rt_kprintf("[Hook] Scheduler: %s -> %s\n", from->name, to->name);elsert_kprintf("[Hook] Scheduler: First run -> %s\n", to->name);
}// 3. 定时器Hook回调函数
static void timer_timeout_hook(struct rt_timer *timer)
{rt_kprintf("[Hook] Timer timeout: %s\n", timer->parent.name);
}// 4. 内存Hook回调函数
static void malloc_hook(void *ptr, rt_uint32_t size)
{rt_kprintf("[Hook] Malloc: ptr=0x%p, size=%d\n", ptr, size);
}static void free_hook(void *ptr)
{rt_kprintf("[Hook] Free: ptr=0x%p\n", ptr);
}// 5. 中断Hook回调函数(配合后面的定时器中断演示)
static void interrupt_enter_hook(void)
{rt_kprintf("[Hook] Interrupt entered, nest: %d\n", rt_interrupt_get_nest());
}static void interrupt_leave_hook(void)
{rt_kprintf("[Hook] Interrupt left, nest: %d\n", rt_interrupt_get_nest());
}// 工作线程1入口函数
static void thread1_entry(void *parameter)
{while (1){// 请求互斥锁rt_mutex_take(mutex, RT_WAITING_FOREVER);// 操作共享资源shared_counter++;rt_kprintf("Thread1: counter = %d\n", shared_counter);// 释放互斥锁rt_mutex_release(mutex);// 线程休眠1秒rt_thread_delay(1000);// 挂起自己(触发线程挂起Hook)rt_thread_suspend(rt_thread_self());}
}// 工作线程2入口函数
static void thread2_entry(void *parameter)
{rt_thread_t thread1 = RT_NULL;// 查找线程1while (thread1 == RT_NULL){thread1 = rt_thread_find("thread1");rt_thread_delay(100);}while (1){// 恢复线程1(触发线程恢复Hook)rt_thread_resume(thread1);// 请求互斥锁rt_mutex_take(mutex, RT_WAITING_FOREVER);// 操作共享资源shared_counter *= 2;rt_kprintf("Thread2: counter = %d\n", shared_counter);// 释放互斥锁rt_mutex_release(mutex);// 线程休眠2秒rt_thread_delay(2000);}
}// 定时器回调函数
static void timer_callback(void *parameter)
{rt_kprintf("Timer: Current counter = %d\n", shared_counter);
}int main(void)
{rt_thread_t thread1, thread2;// 初始化互斥锁mutex = rt_mutex_create("mutex", RT_IPC_FLAG_FIFO);if (mutex == RT_NULL){rt_kprintf("Create mutex failed!\n");return -1;}// 创建线程1thread1 = rt_thread_create("thread1",thread1_entry,RT_NULL,THREAD_STACK_SIZE,THREAD_PRIORITY,THREAD_TIMESLICE);if (thread1 != RT_NULL)rt_thread_startup(thread1);elsert_kprintf("Create thread1 failed!\n");// 创建线程2thread2 = rt_thread_create("thread2",thread2_entry,RT_NULL,THREAD_STACK_SIZE,THREAD_PRIORITY + 1, // 优先级比线程1高THREAD_TIMESLICE);if (thread2 != RT_NULL)rt_thread_startup(thread2);elsert_kprintf("Create thread2 failed!\n");// 创建定时器(周期性)timer = rt_timer_create("timer",timer_callback,RT_NULL,3000, // 3秒超时RT_TIMER_FLAG_PERIODIC);if (timer != RT_NULL)rt_timer_start(timer);elsert_kprintf("Create timer failed!\n");// 注册各种Hookrt_thread_suspend_sethook(thread_suspend_hook);rt_thread_resume_sethook(thread_resume_hook);rt_thread_inited_sethook(thread_inited_hook);rt_scheduler_sethook(scheduler_hook);rt_timer_timeout_sethook(timer_timeout_hook);rt_malloc_sethook(malloc_hook);rt_free_sethook(free_hook);rt_interrupt_enter_sethook(interrupt_enter_hook);rt_interrupt_leave_sethook(interrupt_leave_hook);// 动态分配内存(触发malloc Hook)void *ptr = rt_malloc(128);if (ptr)rt_kprintf("Malloc 128 bytes success\n");elsert_kprintf("Malloc failed\n");// 释放内存(触发free Hook)if (ptr)rt_free(ptr);return 0;
}
0voice · GitHub