关于嵌入式:RTThread学习笔记-6RTThread线程间通信学习过程总结

5次阅读

共计 2974 个字符,预计需要花费 8 分钟才能阅读完成。

前两篇文章总结了 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. 线程对信号的解决,能够设置为捕获信号,疏忽信号,应用默认形式解决信号。

原文链接:https://club.rt-thread.org/as…

正文完
 0