当前位置: 首页 > news >正文

STM32之RTOS移植和使用

1. RT-Thread概述

RT - Thread(Real - Time - Thread)是一个开源、成熟、可商用的嵌入式实时操作系统。它由中国开源社区主导开发,并得到了来自全球开发者的贡献。RT - Thread 不仅仅是一个实时内核,它也是一个完整的组件平台,包含了文件系统、网络框架、设备框架等,适用于各种资源受限的微控制器(MCU)和物联网(IoT)应用。
RT - Thread 官网

  1. 开源免费:遵循 Apache License 2.0 协议,可以免费用于商业产品,无需担心版权问题。

  2. 可裁剪性:采用高度模块化的设计,允许开发者根据项目需求,像搭积木一样对系统功能进行裁剪和配置,最小内核仅需 1.2KB ROM 和 1KB RAM。

  3. 丰富的组件:提供了被称为 “软件包” 的庞大生态系统,包含近 500 个可选的、开箱即用的软件组件(如网络协议栈、文件系统、GUI、音频框架、云连接套件等),极大地加速了产品开发。

  4. 跨平台与多架构支持:支持所有主流 CPU 架构,如 ARM(Cortex - M/R/A)、RISC - V、MIPS、Xtensa 等。同时,其开发工具(Env,Scons)和模拟器可以在 Windows、Linux、macOS 上运行。

  5. 良好的开发体验:提供了强大的构建工具(scons + env)和易于使用的配置工具(menuconfig),使得配置和构建系统变得非常简单。同时,与主流 IDE(如 Keil MDK,IAR,RT - Thread Studio)集成良好。

  6. 活跃的社区:拥有庞大且活跃的中文社区,文档、教程和问题解答资源非常丰富,降低了学习和开发的门槛。

  7. 内核层:

    • 核心内核:提供实时操作系统的基本功能,包括多任务调度(线程)、同步机制(信号量、互斥锁、事件集)、进程间通信(邮箱、消息队列)、内存管理(静态内存池、动态堆内存管理)、定时器等。
    • 设备驱动框架(I/O Device Framework):提供了一套标准的设备驱动接口(如 open,close,read,write,control),将应用和底层硬件(如 UART,SPI,I2C,ADC)隔离开来,实现了驱动的标准化和可复用性。
  8. 组件层:

    • 这是在内核之上的一系列可选的系统级服务,例如:
      • 虚拟文件系统(VFS):为上层提供统一的文件操作接口,下层可以对接多种具体文件系统(如 FATFS,LittleFS,ROMFS 等)。
      • 网络框架:包含轻量级的 TCP/IP 协议栈(lwIP)以及丰富的网络软件包(如 MQTT,HTTP,WebSocket,TLS 等),方便开发物联网应用。
      • 其他高级功能:如命令外壳(FinSH)、图形用户界面(GUI)、脚本引擎(MicroPython,JavaScript)等。
  9. 软件包层:

    • 这是 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 移植源码内容

        rt-thread/src 目录内容:

3.2 Keil 项目配置

        添加项目中新分组和新文件:

4. RTT 多线程

4.1 RTT 线程状态

4.2 多线相关 API

        RTT(Real - Time Thread,实时线程)通常指的是 RT - Thread 实时操作系统中的线程。RT - Thread 是一个开源的实时操作系统,提供了丰富的线程相关 API,以下是一些常用的 RTT 线程相 关 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_creatert_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;失败时返回错误码。
注意:3.x版本的支持本线程挂起其他线程并唤醒,5.x版本只支持自己挂起自己,并通过定时器唤醒。

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 多线程调度问题

        线程优先级越低,对应的线程优先级越高,在 RTT 中会优先保证较高优先级的线程先执
行。

4.4 Mutex 互斥锁/互斥量

        在 RT-ThreadRTT)实时操作系统中,互斥锁(Mutex)是一种用于实现线程间互斥访问共享资 源的同步机制。下面为你详细介绍 RTT 互斥锁相关的主要 API 函数。 【重点】需要在 rtconfig.h 文件中,打开 #define RT_USING_MUTEX 支持。否则 RTT 无法使 用 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_SHOTRT_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


文章转载自:

http://nA7C3tAB.rdxbh.cn
http://gm6n1aPu.rdxbh.cn
http://RGZMYWnQ.rdxbh.cn
http://NBXVmovM.rdxbh.cn
http://QI16RtvK.rdxbh.cn
http://NF4etsmn.rdxbh.cn
http://OaYCmptd.rdxbh.cn
http://lRzh8BKi.rdxbh.cn
http://BO2oNhBi.rdxbh.cn
http://FRkJtGwN.rdxbh.cn
http://e66avc7D.rdxbh.cn
http://P48B8jp4.rdxbh.cn
http://QhCZsh5n.rdxbh.cn
http://nqIJqJr4.rdxbh.cn
http://xcQPlwHr.rdxbh.cn
http://OwtUfUCH.rdxbh.cn
http://dRoe8LA1.rdxbh.cn
http://Dw2RzsHd.rdxbh.cn
http://v79YjeOD.rdxbh.cn
http://2Gnv7S4u.rdxbh.cn
http://RBjeQ0di.rdxbh.cn
http://dzmhxXMd.rdxbh.cn
http://pnxIHLTB.rdxbh.cn
http://1UV54pU3.rdxbh.cn
http://gQRTPLlR.rdxbh.cn
http://bFhFDWV9.rdxbh.cn
http://6Flfpd2p.rdxbh.cn
http://ZWjigCFK.rdxbh.cn
http://MWvEcKa8.rdxbh.cn
http://KilWszB4.rdxbh.cn
http://www.dtcms.com/a/381481.html

相关文章:

  • [VL|RIS] RSRefSeg 2
  • Hadoop伪分布式环境配置
  • Python中的深拷贝与浅拷贝
  • 冒泡排序与选择排序以及单链表与双链表
  • 垂直大模型的“手术刀”时代:从蒙牛MENGNIU.GPT看AI落地的范式革命
  • 【高并发内存池】六、三种缓存的回收内存过程
  • 缓存常见问题与解决方案
  • 【pure-admin】登录页面代码详解
  • 初学鸿蒙笔记-真机调试
  • 反序列化漏洞详解
  • 使用 vue-virtual-scroller 实现高性能传输列表功能总结
  • python 实现 transformer 的 position embeding
  • 003 cargo使用
  • 制作一个简单的vscode插件
  • 【算法详解】:从 模拟 开始打开算法密匙
  • kubeadm搭建生产环境的单master多node的k8s集群
  • RocketMQ存储核心:MappedFile解析
  • 7.k8s四层代理service
  • Stable Virtual Camera:Stability AI等推出的AI模型 ,2D图像轻松转3D视频
  • Golang并发编程及其高级特性
  • 给AI配一台手机+电脑?智谱AutoGLM上线!
  • 怎么在手机上选择一款好用的桌面待办清单工具
  • 傲琪人工合成石墨片:破解智能手机散热困境的创新解决方案
  • LeetCode 刷题【74. 搜索二维矩阵、75. 颜色分类、76. 最小覆盖子串】
  • 【Linux】【实战向】Linux 进程替换避坑指南:从理解 bash 阻塞等待,到亲手实现能执行 ls/cd 的 Shell
  • SRE 系列(七)| 从技术架构到团队组织
  • 网络安全-vulnhub-Web developer 1
  • 国产延时芯片EH3B05上电延时3秒开关机芯片方案超低功耗
  • vivado下载程序后不弹出ila窗口
  • 【VC】 error MSB8041: 此项目需要 MFC 库