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


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

    概述

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

    为了避免这种风险,可以通过下述方法改善这种不可靠的传输关系:
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

    讨论

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

    需求:某一个任务需要等待一个事件的触发,才能被执行。
    应用:
    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)下一篇:任务同步总结及环状同步造成的死锁

  • 相关阅读:
    DTC趋势 | 2022年值得关注的10个DTC趋势
    aj-report页面嵌入其他项目
    linux修改ip地址详解
    Spring Boot通过lombok提供的Slf4j省略日志的创建操作
    node.js共享输液检测系统毕业设计源码131105
    文心一言 VS 讯飞星火 VS chatgpt (286)-- 算法导论21.2 5题
    深度学习编译器关键组件
    Java进阶(再论线程)——线程的4种创建方式 & 线程的生命周期 & 线程的3大特性 & 集合中的线程安全问题
    快速排序算法(思路分析) [数据结构][Java]
    一文读懂UTF-8的编码规则
  • 原文地址:https://blog.csdn.net/wangyx1234/article/details/127597020