Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread一般讨论
rt-thread 从信号工作原理谈到其对内核的影响
发布于 2021-12-13 16:49:47 浏览:1376
订阅该版
[tocm] ## 前言 信号 signal,并不是线程间同步的信号量 semaphore。后者是线程间同步机制的一种,而前者是线程间异步通信的一种。 官方文档里对其解释是:“信号(又称为软中断信号),在软件层次上是对中断机制的一种模拟,在原理上,一个线程收到一个信号与处理器收到一个中断请求可以说是类似的。” 信号本质是**软中断**,用来通知线程发生了异步事件,**用做线程之间的异常通知、应急处理**。一个**线程不必通过任何操作来等待信号的到达**,事实上,**线程也不知道信号到底什么时候到达**。线程之间可以互相通过调用 `rt_thread_kill` 发送信号。 以上画线部分是我特意要大家注意的,我们要看待中断回调函数那样,看待信号回调函数**被执行的实机**,但不需要过分担忧的是回调函数**执行时间**,因为**终究信号回调函数还是在线程上下文被执行的**。 从官方文档可以清楚了解到,使用信号很简单,安装信号、解除信号掩码、发送信号、处理信号等几个过程。 更多关于信号的原理详见官方文档 [信号](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/ipc2/ipc2?id=%e4%bf%a1%e5%8f%b7) ### 一个示例引起的血案 官方原版示例笔者就不贴出来了,直接拷贝到自己的项目完美运行。但是,笔者经过如下修改,发现一点儿疑问。 ``` /* 线程 1 的入口函数 */ static void thread1_entry(void *parameter) { ... while (cnt < 10) { ... tick = rt_tick_get(); rt_thread_mdelay(1000); tick = rt_tick_get(); } ... } ``` 把延时时间增长,前后添加测时。多次运行发现 tick 值改变只有 300 (`rt_thread_mdelay(300)`)。这说明了线程响应 signal 后,处理了信号回调函数之后放弃了之前的延时!那么问题来了,应用层想要的延时时间不足,应用层知道吗?答案是,*不知道!* ### rt-thread 中阻塞函数列表 前一段时间在文章 [rt-thread 那些你必须知道的几类 api](https://club.rt-thread.org/ask/article/3204.html) 里总结了 *禁止在中断中调用*、*必须在任务调度器运行以后才能使用*、*不能用在线程自己身上*的几类 api。 可能还缺一种:哪些 api 会引起线程调度,使得当前线程放弃 cpu 使用权——所有调用 `rt_schedule` 的函数都属于这类。这里边又分三种情况,一种是时间片耗尽让出 cpu 使用权;一种是释放资源或者信号让出 cpu 使用权;还有一种是等待资源而被动放弃 cpu。最后这种情况,是有目地的,往往希望有资源可用了之后从阻塞中恢复继续运行,如果线程从阻塞中恢复运行但同时没有资源可用是不是就乌龙了?以下的关注重点也是这类函数。 所有第三类引起线程调度的函数和上面的 `rt_thread_mdelay` 一样,在 signal 面前可能遇到一样的遭遇。大体上,分这么几类: - 延时函数 - 线程间同步机制函数 - 线程间通信机制部分函数(signal除外) - posix 下的 select poll 等接口(可能使用了线程间同步和通信机制) 这几类在遇到 signal 之后行为分别是什么样的? ### 被阻塞函数遇到 signal 后什么反应? #### 延时函数遇到 signal 这个前面已经经过测试的了,它会退出阻塞提前结束延时,但是应用层并不知道是达到延时时间还是有信号。 #### 线程间同步通信机制函数遇到 signal - `rt_sem_take` 线程 error 非 RT_EOK (包括 RT_EINTR)直接返回线程错误状态 ``` /* do schedule */ rt_schedule(); if (thread->error != RT_EOK) { return thread->error; } ``` - `rt_mutex_take` 考虑到了 signal 的影响,返回继续阻塞等待 `time` 时间。这是 ipc 里唯一例外的一个。 ``` /* do schedule */ rt_schedule(); if (thread->error != RT_EOK) { #ifdef RT_USING_SIGNALS /* interrupt by signal, try it again */ if (thread->error == -RT_EINTR) goto __again; #endif /* RT_USING_SIGNALS */ ``` 其它,其余的都和 `rt_sem_take` 一样。 #### 完成量遇到 signal `rt_completion_wait` 返回线程错误状态。 ``` /* do schedule */ rt_schedule(); /* thread is waked up */ result = thread->error; level = rt_hw_interrupt_disable(); } } ... return result; ``` #### select poll 等接口与 signal 因为文件描述符对应的设备不尽相同,设备底层实现 `poll` 的方式可能也千差万别,但是他们大概率是使用上面的线程间同步和通信机制了。 `poll` 实现过程调用个超时等待函数 `poll_wait_timeout` ,它也没有区分超时和信号两种情况。 ``` rt_schedule(); level = rt_hw_interrupt_disable(); } ret = !pt->triggered; rt_hw_interrupt_enable(level); return ret; ``` 我们发现,`rt_sem_take` 结束了阻塞,并可能返回了 `RT_EINTR` ,而 `rt_mutex_take` 继续了循环阻塞。 ### 等待资源而被动放弃 cpu 时怎么应对 signal 才合适? 现做以下约定,等待资源而被动放弃 cpu 的线程在此约定下,当有 signal 的时候会提前结束阻塞,返回应用层,应用层可以根据线程错误状态区别处理。 1. 复位线程错误状态为 `RT_EOK` 。 2. 调用 `rt_schedule` 进行线程调度,线程被阻塞挂起。 3. 从 `rt_schedule` 恢复唤醒,有一定手段通知到应用层(返回线程错误状态),应用层可以区分出是因为资源可用还是因为信号。 - 哪些 api 做到了以上这几点呢? ``` rt_completion_wait rt_sem_take rt_event_recv rt_mb_send_wait rt_mb_recv rt_mq_send_wait rt_mq_recv rt_data_queue_push rt_data_queue_pop rt_mp_alloc ``` - 哪些 api 没有做到以上几点? ``` rt_mutex_take rt_thread_sleep rt_thread_delay rt_thread_delay_until rt_thread_mdelay rt_wqueue_wait ``` 笔者曾经在 gitee 上提交过一个 [issue](https://gitee.com/rtthread/rt-thread/issues/I44JNS) ,当时笔者隐隐中认为 ipc 中的不一致行为总有些隐患,感觉所有的阻塞等待都应该处理一下意外唤醒后的超时等待。却没意识到有什么意外情况可以让这些函数从阻塞等待中提前退出。通过研究 signal 实现原理的过程中发现,这种意外情况还有存在的,只是担忧的问题重点变了,不是处理阻塞等待剩余时间,而是在 signal 的影响下通知应用层的问题。 ### 解决方案 有了上面的梳理,下面的修改方向就有了,改动范围也确定了。 - 几个延时函数返回 `thread->error` 代替目前的 `RT_EOK` ; - `rt_mutex_take` 去掉 `goto __again` 也返回 `thread->error` ; - `rt_wqueue_wait` 返回 `thread->error` 代替目前的 `RT_EOK` 。 - `poll` 目前返回值是 >= 0 的,返回 0 可能是超时,也可能是被信号中断了。暂时不发表修改意见。 ## 结束语 以上搜索不一定完整完全,但应该包括了大部分受到影响的函数。如果看客有发现其它的 api 有不符合上述约定行为的,请留言告知,谢谢! 本人能力有限,文中难免有错误。望各位同仁不吝赐教。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
出出啊
恃人不如自恃,人之为己者不如己之自为也
文章
43
回答
1517
被采纳
342
关注TA
发私信
相关文章
1
有关动态模块加载的一篇论文
2
最近的调程序总结
3
晕掉了,这么久都不见layer2的踪影啊
4
继续K9ii的历程
5
[GUI相关] FreeType 2
6
[GUI相关]嵌入式系统中文输入法的设计
7
20081101 RT-Thread开发者聚会总结
8
嵌入式系统基础
9
linux2.4.19在at91rm9200 上的寄存器设置
10
[转]基于嵌入式Linux的通用触摸屏校准程序
推荐文章
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
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
xiaorui
1
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部