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

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

3天内不再提示

rt-thread 优化系列(四)信号对 ipc 的影响

出出 来源:出出 作者:出出 2022-06-23 09:51 次阅读

前言

信号 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 里总结了 *禁止在中断中调用*、*必须在任务调度器运行以后才能使用*、*不能用在线程自己身上*的几类 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 */

其它,其余的 ipc 都和 `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 有不符合上述约定行为的,请留言告知,谢谢!

本人能力有限,文中难免有错误。望各位同仁不吝赐教。

相关文章

rt-thread 优化系列(0) SysTick 优化分析

rt-thread 优化系列(一) 之 过多关中断

rt-thread 优化系列(二) 之 同步和消息关中断分析

rt-thread优化系列(三)软定时器的定时漂移问题分析


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

    关注

    11

    文章

    2639

    浏览量

    75385
  • IPC
    IPC
    +关注

    关注

    3

    文章

    306

    浏览量

    51348
  • signal
    +关注

    关注

    0

    文章

    110

    浏览量

    24759
  • RT-Thread
    +关注

    关注

    31

    文章

    1148

    浏览量

    38867
收藏 人收藏

    评论

    相关推荐

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

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

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

    漂移问题分析rt-thread 优化系列信号ipc 的影响
    发表于 07-26 14:56

    RT-Thread编程指南

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

    RT-Thread开发,如何有效学习RT-Thread的五个步骤

    RT-Thread推出RT-Thread Inside战略开放RT-Thread开发平台授权合作,与硬件十万个为什么合作首次推出第一款RT-Inside的开发板——iBox物联网开发套
    的头像 发表于 09-25 09:55 3.4w次阅读
    <b class='flag-5'>RT-Thread</b>开发,如何有效学习<b class='flag-5'>RT-Thread</b>的五个步骤

    RT-Thread开源作品秀】基于RT-Thread的星务平台研究

    本作品为了验证星务软件在RT-Thread系统运行的可行性,底层是否能够驱动星务软件,同时扩展RT-Thread应用范围。ART-Pi作为卫星下位机,...
    发表于 01-25 18:26 5次下载
    【<b class='flag-5'>RT-Thread</b>开源作品秀】基于<b class='flag-5'>RT-Thread</b>的星务平台研究

    RT-Thread隐藏的宝藏之completion

    completion 直接翻译过来是完成,所以我更愿意称 rt_completion 为 完成量。在 RT-Thread 的文档中心 中讲线程间通讯(IPC)时,只介绍...
    发表于 01-25 19:27 0次下载
    <b class='flag-5'>RT-Thread</b>隐藏的宝藏之completion

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

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

    RT-Thread全球技术大会:Kconfig在RT-Thread中的工作机制

    RT-Thread全球技术大会:Kconfig在RT-Thread中的工作机制               审核编辑:彭静
    的头像 发表于 05-27 14:49 1236次阅读
    <b class='flag-5'>RT-Thread</b>全球技术大会:Kconfig在<b class='flag-5'>RT-Thread</b>中的工作机制

    RT-Thread全球技术大会:RT-Thread测试用例集合案例

    RT-Thread全球技术大会:RT-Thread测试用例集合案例           审核编辑:彭静
    的头像 发表于 05-27 16:34 1779次阅读
    <b class='flag-5'>RT-Thread</b>全球技术大会:<b class='flag-5'>RT-Thread</b>测试用例集合案例

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

    RT-Thread 简介 作为一名 RTOS 的初学者,也许你对 RT-Thread 还比较陌生。然而,随着你的深入接触,你会逐渐发现 RT-Thread 的魅力和它相较于其他同类型 RTOS
    的头像 发表于 07-09 11:27 3996次阅读
    <b class='flag-5'>RT-Thread</b>学习笔记 <b class='flag-5'>RT-Thread</b>的架构概述

    RT-Thread已经全面支持极海APM32F1系列MCU

    近日,RT-Thread 和其高级会员合作伙伴极海半导体宣布:正式完成APM32F4系列MCU的RT-Thread 物联网操作系统适配及RT-Thread Studio IDE的支持。
    发表于 08-30 09:45 983次阅读

    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 7次下载
    <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 7次下载
    <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 2580次阅读
    基于<b class='flag-5'>RT-Thread</b> Studio学习