RT-Thread学习笔记 --(6)RT-Thread线程间通信学习总结

RT-Thread线程间通信学习总结

前两篇文章总结了RT-Thread多线程以及多线程同步的学习过程,关于前两篇学习总结,可以查看以下链接:

RT-Thread学习笔记 --(4)RT-Thread多线程学习总结

RT-Thread学习笔记 --(5)RT-Thread线程间同步学习总结

本篇文章继续总结关于RT-Thread多线程相关的最后一个重要知识点:线程间通信。前面的文章多次提及到,一个大的任务拆分为多个小任务,这些小任务之间必然存在着各种各样的关系,导致这些小任务的线程不能各自为政,必须要考虑其他任务线程的运行情况。

既然已经有了线程间同步,可以让多个线程之间进行相互沟通,那为啥还需要线程间通信呢?线程间通信到底是什么东西,这种方式有什么应用场景?

关于多线程之间的通信,RT-Thread官方提供了比较丰富的文档作为参考,具体可以查看以下链接:

https://www.rt-thread.org/document/site/programming-manual/ipc2/ipc2/

本文尝试从以下几个方面总结一下RT-Thread线程间通信的学习过程

 

线程间通信的相关概念

什么是线程间通信?通信,顾名思义,就是双方需要进行沟通与对话。通俗地概括,就是A线程在工作运行期间,有某些数据或者信息,要告诉B线程,让B线程接收到这些数据或信息后,能够继续完成指定的任务和工作。

两个线程之间为什么要进行通信呢?还是那句话,多个任务线程并不是独立的,它们在工作的时候是需要根据业务场景进行一定的沟通的,还是以音乐播放器举例,当歌词读取线程把歌词从硬盘里面读出来了,要把这一串读到的歌词告诉给显示线程,让它把歌词显示出来。这个“告诉”的动作,就是通过线程间通信来进行的。

既然都是为了协调线程的工作状态,线程间同步和线程间通信这两者有什么区别呢?区别就是线程间同步能做的事情太有限了,线程间同步只是告诉一下对方“别跑太快,等等我嘛~”,而线程间通信,就是有一大堆的数据和信息要告知对方,万一A线程有很多话要跟B线程说,线程同步这种方式就不能满足要求了,所以需要线程间通信。

 

线程间通信的方式

针对RT-Thread实时操作系统,线程间通信主要有三种方式:邮箱,消息队列,信号。这三种线程间通信机制都有各自的特点,在实际开发工作里面,需要根据不同的应用场景进行区分使用。

邮箱是线程间通信的其中一种方式,这个邮箱的概念,跟我们生活中使用的邮箱概念,其实是大同小异的,在生活中,如果我们有信件要寄,就把信件往邮筒一扔就可以了,邮局会负责把信件送往目的地。

同样的道理,当A线程有信件(即数据)要发送给B线程,只需要调用操作系统提供的邮箱相关接口函数,把数据发送出去,操作系统就会负责把数据转发到目标线程,整个转发过程是怎样实现的,收和发的线程都不需要关心。

使用邮箱进行线程间通信,特点是开销低,效率高。这是因为,每个邮件信息最多只能是4个字节的内容,所以,这个邮件信息可以是某个数据块的指针,通过指针传递的方式,来传输更多的数据。

邮箱在使用过程中,可能会存在邮箱空或邮箱满的情况,在邮箱空的情况下,接收邮件的线程会选择挂起等待,或者等超时时间到来。在邮箱满的情况下,发送邮件的线程会选择挂起或直接返回一个邮箱满的返回值。

系统内核提供以下邮箱相关的API函数接口,如下图所示。

消息队列是另外一种比较常用的线程间通信方式,相当于邮箱的扩展。跟邮箱不同的是,消息队列是可以接收不定长的数据的,并且把这个不定长的数据复制到自身线程的内存空间。

消息队列其实就是一个数据存储空间,这个存储空间遵循先进先出的原则,也就是说,不管是什么消息,等待消息的线程获得的是最先进入队列的消息。

消息队列控制块里面,其实有两个链表,一个链表是用来挂接空的消息块(也就是没有内容的消息队列),另一个链表是用来挂接存有消息的消息块,具体抽象如下图所示。

当线程A要发送一个消息时,先从空闲消息块链表取出一个块空间,把消息装进去后,把这个消息块挂接到非空消息块链表的队尾。如果使用紧急方式发送消息,则把该消息块挂接到非空消息链表的队首。线程获取消息的时候,总是会获取链表头的消息的。

系统内核提供以下消息队列相关的API函数接口,如下图所示。

信号,在软件层次上其实相当于一种软中断的方式,这种中断机制是操作系统模拟出来的,一个线程收到一个信号,跟硬件处理器收到一个硬件中断请求,这个过程基本上是类似的。

当一个线程在正常运行期间,如果其他线程有突发的事件或异常通知需要处理,就可以通过信号的方式发送出去,线程在正常运行期间不需要等待信号的到来(因为不知道信号什么时候会到来)。

收到信号的线程,对各种信号的处理有以下三种方法:

1、类似中断的处理程序,可以针对需要处理的信号指定处理函数,由该函数来处理。

2、直接忽略某个信号,对该信号不做任何处理,就像未发生过一样。

3、使用系统保留的默认值来处理该信号。

系统内核提供以下信号相关的API函数接口,如下图所示。

 

多线程通信的应用示例

多线程通信的应用示例,主要是为了验证邮箱,消息队列,信号的API接口函数,并且通过实验现象观察这三种线程通信方式的运行情况。

示例源码下载链接:https://github.com/embediot/rtthread_study_notes

邮箱示例主要是初始化了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、线程对信号的处理,可以设置为捕捉信号,忽略信号,使用默认方式处理信号。

 

  • 3
    点赞
  • 9
    收藏
  • 打赏
    打赏
  • 0
    评论
概述随着物联网应用的不断发展,传统的传输技术在各个物联网行业应用方面渐渐不能满足我们的需求,传统的局域网技术,如2.4GHz的WiFi,蓝牙、Zigbee等,以及传统广域网技术2G/3G/4G等无线技术,不能同时兼顾远距离和低功耗。直到在低功耗广域网Low Power Wide Area Network, LPWAN技术出现后,能在保证更远距离的通信传输的同时,最大限度的降低功耗,节约传输成本。 本应用使用ART-PI开发板,NUCLEO-L452开发板以及本人自制的扩展板,组成LORA采集端和接收转发端,即使在条件恶略的环境下也能采集数据并通过LORA传送接收并转发至云平台. 开发环境硬件:ART-PI开发板NUCLEO-L452开发板 LORA采集扩展板(安信可Ra-02,DHT11) LORA接收扩展板(安信可Ra-02,W5500,sp485) RT-Thread版本:RT-Thread4.03(ART-PI开发板)RT-Thread4.02(NUCLEO-L452开发板) 开发工具及版本:RT-ThreadStudio V2.0 STM32CuBeMx V6.1.0 RT-Thread使用情况概述内核部分:主要使用了线程管理 时钟管理 组件部分:FinSH控制台,netdev网卡,SAL套接字抽象层,ulog日志 软件包部分:cjson webclient,pahomqtt,fal,wiznet,dhtxx 硬件框架采集端:简单的LORA模组,通过SPI跟板卡通信,以及一个可控LDO和AHT10和BH1750,以LDO控制AHT10和BH1750以达到低功耗的效果. 接收端:一个LORA模组,一个W5500芯片,SPI通信,以及一个SP485. 主要部分就是LORA模组以及W5500,本设计使用立创EDA设计,W5500参考自立创官方团队. 软件框架说明ART-PINUCLEO-L452软件模块说明ART-PI(接收端),上电自动初始化LORA和W5500,等待W5500连接上网络,这里通过判断网卡的状态,当link_up状态后,开始连接mqtt服务器,就可以把LORA接受的数据通过MQTT发送至平台. NUCLEO-L452(采集端),上电初始化软件IIC,直接采集同一总线下AHT10和BH1750的数据,并通过LORA直接发送出去.(备注:因时间关系,采集端的低功耗并没有做,年前估计没时间完善了,以后有时间继续完善) 演示效果视频展示: 比赛感悟这次比赛又学到了不少东西,最主要的就是I2C总线设备和netdev 网卡,刚开始板载WIFI使用时无法使用W5500,因为默认网卡的原因,后来查询RT-Thread 文档中心,看看API和示例,轻松解决.还有就是使用I2C总线设备,刚开始一直想要使用硬件IIC和软件包去驱动AHT10和BH1750,后来发现软件IIC加PIN设备轻松解决,对着文档中心的例子,轻松举一反三出BH1750的程序.所以感觉RT-Thread的文档是真的全乎,所有自己解决不了的东西文档中心都有.但很遗憾的是这次由于出差的原因并没能很完美的展现出来作品,其中ART-PI扩展板上的485并没写到程序中,IWIFI也没应用到(现在是以太网),采集端的低功耗也没有做,年后一定把晚上出来!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

工程师进阶笔记

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值