FreeRTOS事件组(Event Group)的工作机制分析

一、事件组概念

事件组是FreeRTOS提供的多任务同步、多事件标志等待内核对象,本质是一组按位管理的事件标志位(bit),由一个无符号整数存储标志:

1.每一个bit代表一件独立事件(bit0=事件0、bit1=事件1......);

2.任务可置位事件、等待一组事件、清除事件位;

3.支持两种等待逻辑:等待所有指定位全部置1(与逻辑)、等待任意一个指定位置1(或逻辑);

4.优势:单个事件组可替代多个二值信号量,简化多事件同步场景。

限制:

默认事件组存储类型:EventBits_t(16位/32位,由configUSE_16_BIT_TICKS决定,一般32位,最多32个独立事件);

中断中只能调用置位事件API,不能阻塞等待事件;

等待事件时可选择自动清除匹配到的事件位或保留标志位。

二、数据结构

1.事件组句柄结构体EventGroup_t

uxEventBits:核心存储,全局共享事件状态;

xTasksWaitingForBits:阻塞链表,所有等待事件未满足的任务挂在此链表,内核统一唤醒。

三、API与底层行为

1.创建事件组xEventGroupCreate()

1.从堆分配EventGroup_t内存;

2.uxEventBits初始化为0(所有事件清零);

3.初始化阻塞任务链表;

4.返回句柄,失败返回`NULL`。

2.置位事件xEventGroupSetBits()中断版本xEventGroupSetBitsFromISR()

完整执行流程:

1.进入临界区保护(防止多任务并发修改标志);

2.按入参uxBitsToSet对uxEventBits做按位或,对应bit置1

uxEventBits |= uxBitsToSet;

3.遍历阻塞链表xTasksWaitingForBits,逐个检查每个等待任务的等待条件:

任务保存了两个参数:等待掩码uxBitsWait、等待模式(全部匹配/任意匹配);

模式1(pdTRUE,等待所有位):(uxEventBits & uxBitsWait) == uxBitsWait`

模式2(pdFALSE,等待任意位):(uxEventBits & uxBitsWait) != 0

4.对条件满足的任务:

从阻塞链表移除,加入就绪链表;

若任务设置了「自动清除标志位」,匹配完成后清除对应bit;

5.退出临界区,触发任务调度(若有高优先级任务就绪则切换上下文)。

关键点:一次置位多个bit时,会一次性唤醒所有满足条件的等待任务,支持一对多同步。

3.等待事件xEventGroupWaitBits()

函数原型:

内部执行机制:

1.临界区读取当前事件标志uxEventBits;

2.判断当前标志是否满足等待条件:

满足:直接返回当前事件值,若xClearOnExit=pdTRUE则清除匹配 bit;不阻塞;

不满足:进入阻塞流程;

3.阻塞流程:

将当前任务、等待掩码、等待模式存入任务TCB;

任务从就绪链表移出,加入事件组阻塞链表;

设置阻塞超时时间,退出临界区;

触发任务调度,CPU切换至其他就绪任务;

4.唤醒/超时返回:

被置位API唤醒:条件满足,按参数决定是否清除bit,返回事件标志;

超时自动唤醒:返回当前事件标志(未满足条件)。

自动清除标志的两种场景差异:

1.xClearOnExit = pdTRUE:任务拿到事件后自动清位,独占式事件(典型:任务接收单次触发信号);

2.xClearOnExit = pdFALSE:标志永久保留,多任务可同时读取同一个事件位,共享式事件(典型:状态标记,多个任务读取同一设备就绪标志)。

4.手动清除事件xEventGroupClearBits()

直接对uxEventBits做按位与取反,清除指定bit:

uxEventBits &= (~uxBitsToClear);

仅修改标志,不会唤醒任何任务,仅主动清零状态。

5.获取当前事件xEventGroupGetBits()

临界区内读取uxEventBits,无阻塞,仅查询状态。

四、事件组同步任务实验

配置:

五、阻塞与唤醒流程

场景:任务A等待bit0+bit1全部置位;任务B置bit0;任务C置bit1

1.系统启动,事件组bits=0;

1.任务A调用xEventGroupWaitBits(bits0|bits1, auto_clear=1, wait_all=1, portMAX_DELAY);

当前bits不满足,任务A进入事件组阻塞链表,CPU切走;

3.任务B执行xEventGroupSetBits(bit0):

bits变为0b01;遍历阻塞链表,检查任务A条件:缺少bit1,不唤醒;函数返回;

4.任务C执行xEventGroupSetBits(bit1):

bits变为0b11;遍历阻塞链表,任务A条件全部匹配;

将A移出阻塞链表、放入就绪链表;auto\_clear开启,自动清零bit0、bit1;

5.调度器切换到任务A,xEventGroupWaitBits返回匹配的事件掩码,任务A继续执行。

六、两种等待模式对比

设当前事件:bits = 0b1010(bit1、bit3置1),等待掩码wait = 0b1001(bit0、bit3)

1.等待任意(xWaitForAllBits=pdFALSE)

0b1010 & 0b1001 = 0b1000 != 0 → 条件成立,立即唤醒;

只要掩码中任意一个 bit 存在即可。

2.等待全部(xWaitForAllBits=pdTRUE)

0b1010 & 0b1001 = 0b1000 != 0b1001 → 条件不成立,继续阻塞;

掩码内所有 bit 必须同时置 1 才满足。

七、中断中使用限制

仅允许xEventGroupSetBitsFromISR,禁止xEventGroupWaitBits:

1.中断上下文不能阻塞,无任务调度机制,阻塞会直接死机;

2.中断中只能修改事件标志,通过置位被动唤醒阻塞任务;

3.中断置位底层:使用中断保护、尾部回调xHigherPriorityTaskWoken,需在ISR末尾手动portYIELD_FROM_ISR(xHigherPriorityTaskWoken)触发调度。

八、事件组与信号量的区别

1.二值信号量:仅单一同步源,只能标记"有/无",无法区分多种事件;

2.计数信号量:资源计数,用于资源占用释放;

3.事件组:多bit状态标记,同时等待多个事件组合,支持或/与逻辑,适合多条件同步(多传感器就绪、多按键触发、多外设中断汇总)。

使用场景:

多中断汇总:UART、ADC、DMA 中断统一置对应 bit,单个任务等待所有中断标志;

多条件启动:必须收到传感器数据和按键触发两个事件才执行业务;

多任务共享状态:全局设备就绪标志,多个读取任务同时查询。

九、工作机制总结

1.存储层:32位bit数组统一管理所有事件状态;

2.修改层:任务/中断可置位、清零、查询标志;修改后遍历阻塞任务链表校验等待条件;

3.阻塞层:条件不满足的任务挂载专属阻塞链表,释放CPU;

4.唤醒层:置位事件时批量校验,匹配条件任务转入就绪态,触发调度;

5.逻辑层:内置等待全部/等待任意两种位匹配算法,支持自动清除事件标记,适配多事件同步场景。

相关推荐
xiaoxiangsiyan1 小时前
RHCE2026云原生路线EX188和EX288完整备考指南
运维·网络·云原生·自动化
Meya11271 小时前
RFID 机房资产管理系统:告别手工台账,实现资产全流程自动管控
大数据·服务器
西安景驰电子1 小时前
《PTP精确时间协议系列》第二篇:工程部署、调试与性能优化
运维·服务器·网络·数据库·windows·性能优化
虹科网络安全3 小时前
KnowBe4 SAT 是什么?安全意识培训平台功能与应用详解
网络
艺杯羹3 小时前
古典密码学攻防演进全景:从凯撒移位、频率分析到一次一密与恩尼格玛机破译
网络·人工智能·安全·网络安全·密码学·密码安全
发量惊人的中年网工3 小时前
多品牌酒店门店如何集中管控网络?SD-WAN 实现住客网与业务网隔离的实践
网络·组网
菜是原罪3 小时前
ECS CPU 100% 故障排查与安全事件复盘报告
运维·服务器·网络安全
12.=0.4 小时前
【REVIEW_C】【持续更新】
服务器·前端·javascript
皮皮虾❀4 小时前
广州云服务器价格:阿里云代理商折扣报价单指南
运维·服务器·阿里云