Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread学习营
rt-thread 那些你必须知道的几类 api
发布于 2021-12-07 14:51:18 浏览:3820
订阅该版
[tocm] ## 前言 多任务系统,线程和中断是两个竞争关系的各自独立的实体。很多 api 是禁止在中断中调用的。 和线程运行息息相关的函数,要求必须在任务调度运行起来以后才能使用。 以及,一些 api 被设计出来是用来在某线程操作另外一个线程,是不可以某线程针对自己使用的。 今天就说说哪些 api 禁止在中断中调用、哪些必须在任务调度器运行以后才能使用、哪些不能线程用在自己身上。 ### 禁止在中断调用的 api 列表 内存堆操作类 ``` rt_system_heap_init rt_malloc rt_realloc rt_free ``` 内存池类 ``` rt_mp_create rt_mp_delete rt_mp_alloc ``` 内核对象类 ``` rt_object_allocate rt_object_find ``` idle 线程 ``` rt_defunct_execute ``` ipc 同步和消息机制类 ``` rt_sem_create rt_sem_delete rt_mutex_create rt_mutex_trytake rt_mutex_delete rt_event_create rt_event_delete rt_mb_create rt_mb_delete rt_mq_create rt_mq_delete ``` 完成量 ``` rt_completion_wait ``` 队列类 ``` rt_wqueue_wait rt_data_queue_push rt_data_queue_pop ``` 延时 ``` rt_thread_sleep rt_thread_delay rt_thread_delay_until rt_thread_mdelay ``` > *注:源码中摘录,并无理论考证,更无实际验证* 所有被禁止在中断中调用的函数都有个相似的特征 —— 它可能是阻塞的,导致中断无法短时间内返回;或者它想调用可能发生阻塞的 api 。 任何引用了他们的函数也被带跑了,不能在中断中使用。 #### RT_DEBUG_NOT_IN_INTERRUPT 调试宏定义 rt-thread 定义了一个宏,当我们开启调试的时候,它可以帮我检查当前函数是否被中断调用了。其实现如下: ``` #define RT_DEBUG_NOT_IN_INTERRUPT \ do \ { \ rt_base_t level; \ level = rt_hw_interrupt_disable(); \ if (rt_interrupt_get_nest() != 0) \ { \ rt_kprintf("Function[%s] shall not be used in ISR\n", __FUNCTION__); \ RT_ASSERT(0) \ } \ rt_hw_interrupt_enable(level); \ } \ while (0) ``` 当你在源码里看见某个函数体中有一行 #### 引用 RT_DEBUG_NOT_IN_INTERRUPT 调试宏的几点问题 1. rt-thread 中有多处引用了这个宏,上面函数列表里绝大部分有; 2. 有一些没有,比如 memheap.c 文件中的 `rt_memheap_alloc` `rt_memheap_realloc` 等操作。 3. 仔细查看引用了 `RT_DEBUG_NOT_IN_INTERRUPT` 的所有函数,有部分使用宏的地方真让人揪心,以 `rt_defunct_execute` 函数为例: ``` static void rt_defunct_execute(void) { // Loop until there is no dead thread. // So one call to rt_defunct_execute // will do all the cleanups. */ while (1) { register rt_base_t level; rt_thread_t thread; void (*cleanup)(struct rt_thread *tid); #ifdef RT_USING_MODULE struct rt_dlmodule *module = RT_NULL; #endif RT_DEBUG_NOT_IN_INTERRUPT; // <<-- ``` 为什么放 while 里?不是 while 之前?不应该放到函数开头醒目的地方吗?有人反驳了啊,放哪儿不一样,放哪也是一行代码的事儿! > RT_DEBUG_IN_THREAD_CONTEXT 也有用样的使用不当,放到某个判断内部,而不是函数开头就引用。 4. 那么我还有个疑问:这是 idle 线程的内部调用的局部函数,会被中断调用了?!谁有权限在中断里引用它?!**`rt_defunct_execute` 函数应该从上面的列表里删除掉**,这个笔者已经在 github 上 pr 修改过了 ### 必须在线程上下文调用的 api 列表 信号 ``` rt_signal_wait ``` ipc 同步和消息机制 ``` rt_sem_take rt_mutex_take rt_mutex_release rt_event_recv rt_mb_send_wait rt_mb_recv rt_mq_send_wait rt_mq_recv ``` 线程操作类 ``` rt_thread_detach rt_thread_delete rt_thread_yield rt_thread_delay rt_thread_delay_until rt_thread_mdelay rt_thread_suspend rt_thread_resume ``` 其它 ``` rt_tick_get rt_enter_critical rt_exit_critical ``` 可以这么说,任务调度器启动前,只允许 init/create/startup 某线程。 虽然,没有发现有谁在任务调度器启动前调用 `rt_thread_suspend` ,但是,有一大批人想使用 `rt_thread_mdelay` 几个延时函数。以上这几个函数开头都应该添加 `RT_DEBUG_IN_THREAD_CONTEXT` 检测,在源码中用于明示此 api 的使用限制。 #### RT_DEBUG_IN_THREAD_CONTEXT 调试宏定义 首先,贴出来它的定义 ``` #define RT_DEBUG_IN_THREAD_CONTEXT \ RT_DEBUG_NOT_IN_INTERRUPT; \ do \ { \ rt_base_t level; \ level = rt_hw_interrupt_disable(); \ if (rt_thread_self() == RT_NULL) \ { \ rt_kprintf("Function[%s] shall not be used before scheduler start\n", \ __FUNCTION__); \ RT_ASSERT(0) \ } \ rt_hw_interrupt_enable(level); \ } \ while (0) #else #define RT_DEBUG_NOT_IN_INTERRUPT #define RT_DEBUG_IN_THREAD_CONTEXT #endif ``` > 注:此定义代码略有改动。 在线程上下文调用的函数有两个特征: 1. 不能在中断中调用。 2. 不能在任务调度器启动前调用,必须线程启动后,被线程入口函数调用。 因此,函数体中添加了此宏引用的函数,也不能在中断响应过程中被调用。 > 鉴于此,本篇开头的***“禁止在中断调用的 api 列表” 需要进行扩充,添加上 “必须在线程上下文调用的 api 列表” 中的所有 api***。 ### 不能用在线程自己身上的 api 首先,这类 api 有个特征,那就是形参有个 rt_thread_t 类型参数。 ``` rt_thread_detach rt_thread_delete ``` 这俩不多说,一个针对静态线程对象,一个针对动态线程对象。作用均是退出线程、清理线程。当前线程退出可以直接从 while 循环里跳出来,从线程入口函数 return 就可以。 `rt_thread_startup` 当一个线程正在运行的时候,它自己再 startup 自己是不是就很诡异了。 `rt_thread_resume` 线程挂起由得自己,唤醒就由不得自己了。 `rt_thread_control` 控制某线程的动作可能有:改变优先级、启动线程、关闭线程、以及多核cpu上绑定线程到某 cpu。某线程偷偷修改自己的运行优先级也说得过去;自己想换个 cpu 核心做依靠,看似也可以,但是,知道当前核的感受吗?有 cpu 资源可用已经不错了,不是吗? 因此,这个 api 只能用来修改自己的优先级。 > 特别的,目前 rt-thread 只支持当前线程自己主动 suspend ,然后等待中断或者其它线程 resume 它。而且,仅限于定时、线程间同步和通信机制里使用。不支持 A 线程 suspend B 线程,然后某个时机再 resume B。不支持 `rt_thread_suspend` `rt_thread_resume` 直接调用。 虽然 `rt_thread_detach` `rt_thread_delete` 用来退出线程,但是,不了解线程运行机制,千万别随意使用这俩函数退出其它线程。如果有需要,使用消息机制让现在自己跳出线程入口函数的 while 循环,自己从线程入口函数返回,这样更安全可靠。 ## 结束 今天就这些了,明天继续。 感谢您的阅读,欢迎各位提出意见,对文中的不当之处不吝赐教。
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
出出啊
恃人不如自恃,人之为己者不如己之自为也
文章
43
回答
1517
被采纳
342
关注TA
发私信
相关文章
1
stm32f407+lan8720 lwip2.0 作业提交
2
玩溜GD32303E-EVAL BSP系列(五)----设备连接网络
3
onenet应用连不上云端
4
【文件系统】晴天文件匹配
5
rtt semc sdram 基于操作系统怎么初始化驱动设备
6
RT-Thread移植笔记
7
RT-Thread内核移植+LoIIs+STM32F103C8+StdLib
8
EVN编译报错,求助大神
9
【内核和外设学习营】十里 简单LED闪亮测试
10
【内核和外设学习营】 十里 串口指令控制RGB灯点亮的颜色
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
MicroPython
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
15
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
RTT_逍遥
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部