用事件组实现多事件的单向同步

用事件组实现多事件的单向同步

概述

相比二值信号量用于处理一个事情的发生,事件组是处理一组事件发生的同步组件。
在这里插入图片描述
事件组可以看作若干个二值信号量的组合,事件组中的每一个 bit 都代表某事件是否发生。此外,事件组还提供了如下的功能:

1)处理不同事件的逻辑关系的功能。可以是逻辑与,即所有事件都发生(对应所有的bit位都置位)才触发某种行为。也可以是逻辑或,即关注的事件中,只要发生一个(对应关注的bit位中有至少一个置位)就触发某种行为。

2)可选择的清除功能,即对应的事件触发后,是否将该事件的 bit 位复位。在不清除对应 bit 位的情况下,可以实现唤醒多个等待该 bit 的 任务(仅最后一个接收事件的任务负责清除该事件),实现“广播”功能。

虽然上节讲述的计数信号量可以用于多任务的同步(通过循环获取或者释放信号量实现),但当信号有多个发送方发送到接收方时,接收方并不知道当前正在处理的信号是哪个发送方发送的。使用事件组可以让不同的发送方使用不同的 bit位,如此接收方可以知道是哪个发送方正在发送事件。

事件组的优势:

1)便于实现多个事件的同时同步,比如在一个任务里监听多个事件(每创建一个任务都要消耗较多资源,因此仅创建一个任务的情况下能节省很多资源)。这些事件可以是多个中断、多个任务等。

2)接收方可以选择是否消耗掉该事件(即使用后是否对该 bit 进行清零)。

3)接收方可以通过 bit 位知道此时发送事件的发送方,从而对不同的发送方可以执行差别化的处理。

不足:

1)虽然可以解决识别发送方的需求,但无法进一步地说明发送信号的目的(只能说有事件发生了,但具体是什么不知道)。

2)每个标志位只能取 0 或 1,无法对事件进行计数。因此,当多次向任务设置同一个标志位,但任务没有及时对该标志位进行清零的话,则等效于仅设置了一次该标志。

需求及功能解析

示例演示事件组的基本使用方法,即任务1、任务2向任务3通过事件组发送事件,任务3接收事件,并打印是哪个任务在发送事件。

事件组的操作主要是创建、设置bits、等待bits:

/* 创建一个事件组,返回它的句柄。
 * 此函数内部会分配事件组结构体 
 * 返回值: 返回句柄,非NULL表示成功
 */
EventGroupHandle_t xEventGroupCreate( void );

/* 设置事件组中的位
 * 返回值: 返回原来的事件值(没什么意义, 因为很可能已经被其他任务修改了)
 */
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, // 事件组
                                    const EventBits_t uxBitsToSet // 设置哪些位?可以用来设置多个位,比如 0x15 就表示设置bit4, bit2, bit0
                                    );
/* 等待事件组中的位
 * 返回值: 如果期待的事件发生了,返回的是解除阻塞时的事件值;
如果是超时退出,返回的是超时时刻的事件值。
*/                                  
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, // 事件组
                                 const EventBits_t uxBitsToWaitFor, // 等待哪些位
                                 const BaseType_t xClearOnExit, // 函数提出前是否要清除事件?pdTRUE: 清除uxBitsToWaitFor指定的位,pdFALSE: 不清除
                                 const BaseType_t xWaitForAllBits, // 是"AND"还是"OR"?pdTRUE: 等待的位,全部为1;pdFALSE: 等待的位,某一个为1即可
                                 TickType_t xTicksToWait ); // 阻塞时间
/* 设置并等待事件组中的位
 * 返回值: 如果期待的事件发生了,返回的是解除阻塞时的事件值;
如果是超时退出,返回的是超时时刻的事件值。
*/  
EventBits_t xEventGroupSync(EventGroupHandle_t xEventGroup, // 事件组
                            const EventBits_t uxBitsToSet, // 设置哪些位?可以用来设置多个位
                            const EventBits_t uxBitsToWaitFor, // 等待哪些位
                            TickType_t xTicksToWait)// 阻塞时间

示例解析

示例输出:

This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, Minimum free heap size: 295340 bytes
TASK3: wait events ok, now bits=0x0003
TASK3: wait events ok, now bits=0x0001
TASK3: wait events ok, now bits=0x0002
TASK3: wait events ok, now bits=0x0001
TASK3: wait events ok, now bits=0x0002
TASK3: wait events ok, now bits=0x0001
TASK3: wait events ok, now bits=0x0002
TASK3: wait events ok, now bits=0x0001
TASK3: wait events ok, now bits=0x0002
TASK3: wait events ok, now bits=0x0001
TASK3: wait events ok, now bits=0x0002

示例中任务1、任务2分别通过 bit0、bit1对任务 3发送事件,任务3可以通过当前事件组的 bits 的值,判断当前哪个任务中有事件发生,如上述 bits=0x0001 的情况,代表任务 1发送了事件;上述 bits=0x0002 的情况,代表任务 2发送了事件;上述 bits=0x0003 的情况,代表任务 1、任务2都发送了事件;

讨论

在进入任务通信的章节后,一定要注意 RTOS 中存在的一个无形的导演,即任务调度器,任务之间的优先级将是通信后系统整体运行实时性、结果正确性的关键因素之一。感兴趣的小伙伴可以回顾RTOS 中的任务调度与三种任务模型
函数 xEventGroupSync()实现了即发送事件,也等待事件的机制,可以用于更复杂的同步场景,如 A 发送事件“酒买好了”,然后进入等待“菜上桌了”事件,然后 B 发送事件“菜上桌了”,然后进入等待“酒买好了”事件,两者都成功等到事件时,则继续向下执行“开干”事件。

总结

1)事件组(EventGroup)提供了管理一组事件的能力,并且可以处理这些事件的逻辑关系。
2)事件组可以用于多任务的同步,但没有提供对事件的计数和更多数据信息的能力。
3)件组的操作主要是创建、设置bits、等待bits。

资源链接

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

3)下一篇:用邮箱实现多事件的单向同步

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

物联网老王

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

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

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

打赏作者

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

抵扣说明:

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

余额充值