RT-Thread学习笔记 --(6)RT-Thread线程间通信学习过程总结
前两篇文章总结了RT-Thread多线程以及多线程同步的学习过程,关于前两篇学习总结,可以查看之前的文章。
本篇文章继续总结关于RT-Thread多线程相关的最后一个重要知识点:线程间通信。前面的文章多次提及到,一个大的任务拆分为多个小任务,这些小任务之间必然存在着各种各样的关系,导致这些小任务的线程不能各自为政,必须要考虑其他任务线程的运行情况。
既然已经有了线程间同步,可以让多个线程之间进行相互沟通,那为啥还需要线程间通信呢?线程间通信到底是什么东西,这种方式有什么应用场景?
关于多线程之间的通信,RT-Thread官方提供了比较丰富的文档作为参考,具体可以查看以下链接:https://www.rt-thread.org/doc...
本文尝试从以下几个方面总结一下RT-Thread线程间通信的学习过程
线程间通信的相关概念
什么是线程间通信?通信,顾名思义,就是双方需要进行沟通与对话。通俗地概括,就是A线程在工作运行期间,有某些数据或者信息,要告诉B线程,让B线程接收到这些数据或信息后,能够继续完成指定的任务和工作。
两个线程之间为什么要进行通信呢?还是那句话,多个任务线程并不是独立的,它们在工作的时候是需要根据业务场景进行一定的沟通的,还是以音乐播放器举例,当歌词读取线程把歌词从硬盘里面读出来了,要把这一串读到的歌词告诉给显示线程,让它把歌词显示出来。这个“告诉”的动作,就是通过线程间通信来进行的。
2.png
既然都是为了协调线程的工作状态,线程间同步和线程间通信这两者有什么区别呢?区别就是线程间同步能做的事情太有限了,线程间同步只是告诉一下对方“别跑太快,等等我嘛~”,而线程间通信,就是有一大堆的数据和信息要告知对方,万一A线程有很多话要跟B线程说,线程同步这种方式就不能满足要求了,所以需要线程间通信。
线程间通信的方式
针对RT-Thread实时操作系统,线程间通信主要有三种方式:邮箱,消息队列,信号。这三种线程间通信机制都有各自的特点,在实际开发工作里面,需要根据不同的应用场景进行区分使用。
邮箱是线程间通信的其中一种方式,这个邮箱的概念,跟我们生活中使用的邮箱概念,其实是大同小异的,在生活中,如果我们有信件要寄,就把信件往邮筒一扔就可以了,邮局会负责把信件送往目的地。
同样的道理,当A线程有信件(即数据)要发送给B线程,只需要调用操作系统提供的邮箱相关接口函数,把数据发送出去,操作系统就会负责把数据转发到目标线程,整个转发过程是怎样实现的,收和发的线程都不需要关心。
使用邮箱进行线程间通信,特点是开销低,效率高。这是因为,每个邮件信息最多只能是4个字节的内容,所以,这个邮件信息可以是某个数据块的指针,通过指针传递的方式,来传输更多的数据。
邮箱在使用过程中,可能会存在邮箱空或邮箱满的情况,在邮箱空的情况下,接收邮件的线程会选择挂起等待,或者等超时时间到来。在邮箱满的情况下,发送邮件的线程会选择挂起或直接返回一个邮箱满的返回值。
系统内核提供以下邮箱相关的API函数接口,如下图所示。
消息队列是另外一种比较常用的线程间通信方式,相当于邮箱的扩展。跟邮箱不同的是,消息队列是可以接收不定长的数据的,并且把这个不定长的数据复制到自身线程的内存空间。
消息队列其实就是一个数据存储空间,这个存储空间遵循先进先出的原则,也就是说,不管是什么消息,等待消息的线程获得的是最先进入队列的消息。
消息队列控制块里面,其实有两个链表,一个链表是用来挂接空的消息块(也就是没有内容的消息队列),另一个链表是用来挂接存有消息的消息块,具体抽象如下图所示。
当线程A要发送一个消息时,先从空闲消息块链表取出一个块空间,把消息装进去后,把这个消息块挂接到非空消息块链表的队尾。如果使用紧急方式发送消息,则把该消息块挂接到非空消息链表的队首。线程获取消息的时候,总是会获取链表头的消息的。
系统内核提供以下消息队列相关的API函数接口,如下图所示。
信号,在软件层次上其实相当于一种软中断的方式,这种中断机制是操作系统模拟出来的,一个线程收到一个信号,跟硬件处理器收到一个硬件中断请求,这个过程基本上是类似的。
当一个线程在正常运行期间,如果其他线程有突发的事件或异常通知需要处理,就可以通过信号的方式发送出去,线程在正常运行期间不需要等待信号的到来(因为不知道信号什么时候会到来)。
收到信号的线程,对各种信号的处理有以下三种方法:
1、类似中断的处理程序,可以针对需要处理的信号指定处理函数,由该函数来处理。
2、直接忽略某个信号,对该信号不做任何处理,就像未发生过一样。
3、使用系统保留的默认值来处理该信号。
系统内核提供以下信号相关的API函数接口,如下图所示。
多线程通信的应用示例
多线程通信的应用示例,主要是为了验证邮箱,消息队列,信号的API接口函数,并且通过实验现象观察这三种线程通信方式的运行情况。
示例源码下载链接:https://github.com/embediot/r...
邮箱示例主要是初始化了2个静态线程,一个静态的邮箱对象,线程 2 发送邮件,共发送 11 次,线程 1 接收邮件,共接收到 11 封邮件,将邮件内容打印出来,并判断结束。
消息队列示例主要初始化了2个静态线程,线程 1 会从消息队列中收取消息,线程 2 定时给消息队列发送普通消息和紧急消息。由于线程 2 发送消息 “I” 是紧急消息,会直接插入消息队列的队首,所以线程 1 在接收到消息 “B” 后,接收的是该紧急消息,之后才接收消息“C”。
信号示例主要是创建了 1 个线程,在安装信号时,信号处理方式设为自定义处理,定义的信号的处理函数为 thread1_signal_handler(),待此线程运行起来安装好信号之后,给此线程发送信号,此线程将接收到信号,并打印信息。
具体示例的实现可以查看工程源码,在thread_communication.h头文件中,打开相应的宏定义开关,重新编译工程并下载到开发板即可。
线程间通信的注意事项
在进行多线程间通信的时候,关于邮箱、消息队列、信号这三种线程间通信方式,有以下一些注意事项:
1.使用邮箱进行线程间通信时,由于一封邮件最多只能是4个字节长度,因此如果要传递较多数据信息,可以使用结构体进行信息封装,通过指针方式进行传递。
2.邮件发送是非阻塞的,因此可以应用于中断服务程序中。但邮件接收是阻塞的,可以设置接收超时的时间,不能在中断服务程序里面使用邮件接收。
3.当邮箱没有邮件且超时时间不为0 ,邮件的接收过程自动变为阻塞方式。当邮箱满了后,发送线程可以选择挂起等待或直接返回邮箱满的错误码。
4.消息队列是一种异步的通信方式,消息队列里面的消息总是遵循先进先出的原则。
5.可以在线程或中断服务程序里面可以给消息队列发送消息,但不能在中断服务程序里面接收消息。
6.可以往消息队列里面发送紧急消息,紧急消息会被放置到消息队列的链表头,会首先被等待的线程获取。
7.信号跟信号量不同,不能混淆两者的概念,信号是软件层面上的一种软中断方式。
8.线程不会用阻塞的方式等待信号的到来,因为线程自身也不知道这个信号(软中断)什么时候会到。
9.线程对信号的处理,可以设置为捕捉信号,忽略信号,使用默认方式处理信号。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
开源软件项目中的版权声明
原文:Copyright Notices in Open Source Software Projects 作者:Andy Updegrove,编译:御坂弟弟 "在一个有许多贡献者的开源软件 OSS (Open Source Software)项目中,一个文件的顶部应该出现什么版权声明?" 这是许多开源开发者共同关心的问题。本文将分享一个在经过了许多社区的讨论后形成的共识。 当源代码、文档和其他内容被贡献给一个 OSS 项目时,这些贡献的版权通常仍由原版权人拥有。 以下是对典型的开源软件项目的讨论,在这个项目中,每个贡献的组织和个人都保留了他们在项目开源软件许可证下提供的版权所有权。在这种情况下,版权作为项目的一部分被授权发布。无论项目是否使用开发者原产地证书 DCO(Developer Certificate of Origin)或贡献者许可协议 CLA(Contributor License Agreement),原版权人都保留其版权。 版权声明 - 社区最佳实践 大多数 LF(Linux Foundation) 项目社区并不要求或建议每个贡献者在贡献的文件中包含他们的版权声...
- 下一篇
smart-doc 2.0.9 发布,Java 零注解 API 文档生成工具
smart-doc 是一款同时支持 java restful api 和 Apache Dubbo rpc 接口文档生成的工具,smart-doc 颠覆了传统类似 swagger 这种大量采用注解侵入来生成文档的实现方法。 smart-doc 完全基于接口源码分析来生成接口文档,完全做到零注解侵入,你只需要按照 java 标准注释编写,smart-doc 就能帮你生成一个简易明了的 markdown 或是一个像 GitBook 样式的静态 html 文档。如果你已经厌倦了 swagger 等文档工具的无数注解和强侵入污染,那请拥抱 smart-doc 吧! 功能特性 支持接口 debug。 零注解、零学习成本、只需要写标准 java 注释。 基于源代码接口定义自动推导,强大的返回结构推导。 支持 Spring MVC,Spring Boot,Spring Boot Web Flux(controller 书写方式)。 支持 Callable,Future,CompletableFuture 等异步接口返回的推导。 支持 JavaBean 上的 JSR303 参数校验规范,支持分组验证。...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- 2048小游戏-低调大师作品
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Red5直播服务器,属于Java语言的直播服务器
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7