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

前言 多任务系统,线程和中断是两个竞争关系的各自独立的实体。很多 api 是禁止在中断中调用的。
和线程运行息息相关的函数,要求必须在任务调度运行起来以后才能使用。
以及,一些 api 被设计出来是用来在某线程操作另外一个线程,是不可以某线程针对自己使用的。
今天就说说哪些 api 禁止在中断中调用、哪些必须在任务调度器运行以后才能使用、哪些不能线程用在自己身上。
禁止在中断调用的 api 列表 内存堆操作类
rt_system_heap_initrt_mallocrt_reallocrt_free 内存池类
rt_mp_creatert_mp_deletert_mp_alloc 内核对象类
rt_object_allocatert_object_find idle 线程
rt_defunct_execute ipc 同步和消息机制类
rt_sem_creatert_sem_deletert_mutex_creatert_mutex_trytakert_mutex_deletert_event_creatert_event_deletert_mb_creatert_mb_deletert_mq_creatert_mq_delete 完成量
rt_completion_wait 队列类
rt_wqueue_waitrt_data_queue_pushrt_data_queue_pop 延时
rt_thread_sleeprt_thread_delayrt_thread_delay_untilrt_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_takert_mutex_takert_mutex_releasert_event_recvrt_mb_send_waitrt_mb_recvrt_mq_send_waitrt_mq_recv 线程操作类
rt_thread_detachrt_thread_deletert_thread_yieldrt_thread_delayrt_thread_delay_untilrt_thread_mdelayrt_thread_suspendrt_thread_resume 其它
rt_tick_getrt_enter_criticalrt_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_detachrt_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 循环,自己从线程入口函数返回,这样更安全可靠。
结束
感谢您的阅读,欢迎各位提出意见,对文中的不当之处不吝赐教。


怎么才能申报呢?推动传感器产业加快发展 深圳重点项目资助最高1亿
打开智能家居市场突破口:标准与系统是关键
荣威RX5、奥迪A5和陆风X2又推出哪几款新车
机器人开始从事高风险的海上钻油平台工作,机器代劳进行作业的时代即将到来
解读,智能制造的主线:智能生产
rt-thread心法系列(一)那些你必须知道的几类 api
戴口罩无法人脸解锁手机?改用指纹识别
对话|需求提升,智能照明控制器更无感智能
高科技时代下的体感试衣镜,它将带来怎样的体验
电动机的电流如何计算
华为荣耀8 Lite亮相工信部 传国行的两个版本本月正式登场
研究发现金属氧化物具有超强的物理储能能力,可提升电池续航3倍
低压干式变压器的技术规范介绍
关于直流电压升压降压变换原理的分析和介绍
ZD-WSK温湿度控制器的功能特点
思灵机器人宣布完成对机器人公司Franka Emika的收购
荣耀9评测:颜值与荣耀8相当,性能不输华为P10,这才是你想要的国产旗舰机
温室大棚结合PoE供电方案发展前景
蓝牙技术联盟发布《2020年蓝牙市场最新资讯》 进一步印证蓝牙技术对市场趋势发展的显著影响力
华为增资至约406.41亿元