使用信号量实现简单双向同步

使用信号量实现简单双向同步

概述

在前述的同步机制中,即便计数信号量队列提供了一定的缓存消息的能力,但只要发送者的速率足够快,再长的缓存空间都有被耗尽的可能,从而导致数据丢失、覆盖的风险。

为了避免这种风险,可以通过下述方法改善这种不可靠的传输关系:
1)发送前先检测是否有可用的空间。

2)发送失败则重发,可以延时一段时间后重发,也可以弹出旧的数据后重发。

3)通过“双向同步”,协调生产者和消费者的供销关系来建立一个平衡的状态。通信的双方相互制约,生产者通过提供消息来同步消费者,消费者通过回复消息来同步生产者,即生产者必须得到消费者的回复后才能进入下一个消息的生产。

本小节重点介绍双向同步的应用与实现。

双向同步适用于两个或者多个任务相互协作完成一项大的任务。

如:打印机,命令处理任务通知启动打印任务,打印任务完成后,通知命令处理任务发送下一条命令。
在这里插入图片描述

需求及功能解析

信号量只提供单向同步的功能,若需双向同步,可借助两个信号量来完成。示例中,通过两个计数信号量完成任务1、任务2的双向同步,其中发送消息时打印,回复消息时打印。

示例解析

示例的 log 输出如下,其中 notify 是发送通知,ACK 是回复的确认消息:

This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, Minimum free heap size: 294424 bytes
TASK1: notify to do, flag=0
TASK2: receive notify
TASK2: send ACK, flag=0
TASK1: receive ACK
TASK1: notify to do, flag=1
TASK2: receive notify
TASK2: send ACK, flag=1
TASK1: receive ACK
TASK1: notify to do, flag=2
TASK2: receive notify
TASK2: send ACK, flag=2
TASK1: receive ACK

注意:单向同步,是说消息的发送是单向的,并不限定收发双方的数量,即示例给出的是一对一的,也可以是一对多,多对多,多对一。当多对多时:发送方并不知道具体哪个任务会收到,接受方并不知道当前的信号是由谁发送的。

讨论

单向同步适用的工作场景:

需求:某一个任务需要等待一个事件的触发,才能被执行。
应用:
1)GPIO 管脚监测报警信号,触发中断,通知任务处理报警事件
2)数据采集任务采集数据,采集后通知数据处理任务去处理数据。

双向同步适用的工作场景:

需求:通信双方需要确保通信过程交互的可靠性,完全不接收信号积压、丢失的情况。
应用:
1)网络数据转发到外设接口,并从外设接口接收响应,最后回复到网络接口的情况。
2)主程序必须等待子程序子程序执行完毕才能继续向下运行的情况。

双向同步时,两个任务的优先级仍旧是需要重点考虑的因素。
在这里插入图片描述
当同时创建的(两任务创建的时机也是考虑因素)两个任务实现双向同步时,任务优先级造成的不同如下:

1)任务1的优先级 > 任务2的优先级,此时是先发第一个同步信号的情况(发送优先)。任务1 发信号 A -> 任务1进入接收信号B的阻塞状态 -> 任务2开始执行 -> 任务 2 进入等信号A的状态 -> 任务2获取到信号 A继续执行 -> 任务 2 发信号 B -> 任务1 接收到信号 B -> 任务 1 重新发送信号 A。依次继续循环。

2)任务2的优先级 > 任务1的优先级,此时是先等第一个同步信号的情况(接收优先)。任务2 等信号 A -> 任务1开始执行-> 任务1发信号A -> 任务2获取到信号 A继续执行 -> 任务2发信号B -> 任务 2 重新进入等待信号A的阻塞状态 -> 任务1 接收到信号 B -> 任务 1 重新发送信号 A。依次继续循环。在接收优先的情况下,实际上可以考虑只用一个信号量A来完成也是可以的,因为优先级高的任务2在重新进入等待信号A之前,一定会占用CPU。整个同步关系变为只有接收任务处理完一次,发送任务才能继续发送下一次信号。但是在 ESP32 的双核系统中,若两个任务被分别分配在两个核心上,则可能会有不一样的情况,读者可探究这种情况下的运行情况。另外,任务之间也可以通过延时改变同步关系,比如高优先级任务发生延时,主动让低优先级任务运行。

信号量、事件组、队列均可以实现这种双向同步。其中,队列可以实现同步时附带数据、事件组可以实现多事件的双向同步。

总结

1)通过“双向同步”,可以协调生产者和消费者的供销关系来建立一个平衡的状态,避免同步信号丢失和被覆盖的情况。

2)信号量只提供单向同步的功能,若需双向同步,可借助两个信号量来完成。

3)信号量、事件组、队列均可以实现这种双向同步。其中,队列可以实现同步时附带数据、事件组可以实现多事件的双向同步。

资源链接

1)Learning-FreeRTOS-with-esp32 系列博客介绍
2)对应示例的 code 链接 (点击直达代码仓库)

3)下一篇:任务同步总结及环状同步造成的死锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物联网老王

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值