0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

rt-thread心法系列(一)那些你必须知道的几类 api

出出 来源:出出 作者:出出 2022-07-08 08:49 次阅读

前言

多任务系统,线程和中断是两个竞争关系的各自独立的实体。很多 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 循环,自己从线程入口函数返回,这样更安全可靠。

结束


感谢您的阅读,欢迎各位提出意见,对文中的不当之处不吝赐教。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • API
    API
    +关注

    关注

    2

    文章

    1478

    浏览量

    61764
  • 多任务系统
    +关注

    关注

    0

    文章

    11

    浏览量

    6866
  • RT-Thread
    +关注

    关注

    31

    文章

    1266

    浏览量

    39864
收藏 人收藏

    评论

    相关推荐

    RT-Thread记录(、版本开发环境及配合CubeMX)

    RT-Thread 学习记录的第篇文章,RT-Thread记录(RT-Thread 版本、RT-T
    的头像 发表于 06-20 00:28 5107次阅读
    <b class='flag-5'>RT-Thread</b>记录(<b class='flag-5'>一</b>、版本开发环境及配合CubeMX)

    RT-Thread记录(二、RT-Thread内核启动流程)

    在前面我们RT-Thread Studio工程基础之上讲RT-Thread内核启动流程.
    的头像 发表于 06-20 00:30 4941次阅读
    <b class='flag-5'>RT-Thread</b>记录(二、<b class='flag-5'>RT-Thread</b>内核启动流程)

    【原创精选】RT-Thread征文精选技术文章合集

    rt-thread心法系列那些必须知道几类
    发表于 07-26 14:56

    RT-Thread编程指南

    RT-Thread编程指南——RT-Thread开发组(2015-03-31)。RT-Thread做为国内有较大影响力的开源实时操作系统,本文是RT-Thread实时操作系统的编程指南
    发表于 11-26 16:06 0次下载

    RT-Thread AI kit开源:轻松实现键部署AI模型至 RT-Thread

    RT-AK 是 RT-Thread 团队为 RT-Thread 实时操作系统所开发的 AI 套件,能够键将 AI 模型部署到 RT-Thread
    发表于 01-25 18:18 3次下载
    <b class='flag-5'>RT-Thread</b> AI kit开源:轻松实现<b class='flag-5'>一</b>键部署AI模型至 <b class='flag-5'>RT-Thread</b>

    RT-Thread新版入门系列教程18讲

    作为名 RTOS 的初学者,也许RT-Thread 还比较陌生。然而,随着的深入接触,会逐渐发现
    发表于 01-25 20:00 0次下载
    <b class='flag-5'>RT-Thread</b>新版入门<b class='flag-5'>系列</b>教程18讲

    rt-thread 心法系列(二) 使用宝典

    接触 rt-thread 已有半年,混论坛也5个半月了,期间遇到过各种奇奇怪怪的棘手问题,有过尴尬,也自信曾经提供过比较妙的应对方案。所以产生了将些典型的使用技巧汇总分享出来的想法,遂有此篇。
    的头像 发表于 07-08 09:41 3062次阅读
    <b class='flag-5'>rt-thread</b> <b class='flag-5'>心法系列</b>(二) 使用宝典

    RT-Thread学习笔记 RT-Thread的架构概述

    RT-Thread 简介 作为名 RTOS 的初学者,也许RT-Thread 还比较陌生。然而,随着的深入接触,
    的头像 发表于 07-09 11:27 4469次阅读
    <b class='flag-5'>RT-Thread</b>学习笔记 <b class='flag-5'>RT-Thread</b>的架构概述

    RT-Thread文档_RT-Thread 简介

    RT-Thread文档_RT-Thread 简介
    发表于 02-22 18:22 5次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> 简介

    RT-Thread文档_RT-Thread 潘多拉 STM32L475 上手指南

    RT-Thread文档_RT-Thread 潘多拉 STM32L475 上手指南
    发表于 02-22 18:23 9次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> 潘多拉 STM32L475 上手指南

    RT-Thread文档_RT-Thread SMP 介绍与移植

    RT-Thread文档_RT-Thread SMP 介绍与移植
    发表于 02-22 18:31 9次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> SMP 介绍与移植

    基于RT-Thread Studio学习

    前期准备:从官网下载 RT-Thread Studio,弄个账号登陆,开启rt-thread学习之旅。
    的头像 发表于 05-15 11:00 3786次阅读
    基于<b class='flag-5'>RT-Thread</b> Studio学习

    怎么知道RT-Thread的CRYPTO设备对M2354支持怎样呢?

    前面碰到了个问题,RT-Thread 支持 MD5,可是 M2354 却不支持,那怎么知道 RT-Thread 的 CRYPTO 设备对 M2354 支持怎样呢?
    的头像 发表于 07-27 15:21 836次阅读
    怎么<b class='flag-5'>知道</b><b class='flag-5'>RT-Thread</b>的CRYPTO设备对M2354支持怎样呢?

    基于 RT-Thread 的 RoboMaster 电控框架(

    。但也正是因为这些优点的覆盖面较广,很多初学者会觉得无从下手,但只要步入 RT-Thread 的大门,就发现她的美好。这系列文档将作为本人基于 RT-Thread 开发 RoboMa
    的头像 发表于 09-19 19:55 723次阅读

    RT-Thread v5.0.2 发布

    一系列令人激动的变化和改进。 以下是些亮点和关键变更:  内核改进: ● 新增了AMP支持。 ● 新增了消息队列的消息优先级。 ● 新增了rt_hw_interrupt_is_disabled
    的头像 发表于 10-10 18:45 1372次阅读
    <b class='flag-5'>RT-Thread</b> v5.0.2 发布