20.1 事件的基本概念
事件是一种实现任务间通信的机制,主要用于实现多任务间的同步,但事件通信只能是事件类型的通信(与队列不同),无数据传输。与信号量不同的是,它可以实现一对多,多对多的同步。即一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。同样,也可以是多个任务同步多个事件。
每一个事件组只需要很少的 RAM 空间来保存事件组的状态。 事件组存储在一个EventBits_t 类 型 的 变 量 中 , 在 STM32 中 , 将configUSE_16_BIT_TICKS 定义为0,那么 uxEventBits 是32位的,有 4个位用来实现事件标志组。
每一位代表一个事件, 任务通过“逻辑与”或“逻辑或”与一个或多个事件建立关联,形成一个事件组。
事件的“逻辑或”也被称作是独立型同步,指的是任务感兴趣的所有事件任一件发生即可被唤醒;事件“逻辑与” 则被称为是关联型同步,指的是任务感兴趣的若干事件都发生时才被唤醒,并且事件发生的时间可以不同步。
多任务环境下, 任务、中断之间往往需要同步操作,一个事件发生会告知等待中的任务,即形成一个任务与任务、中断与任务间的同步。事件可以提供一对多、多对多的同步操作。一对多同步模型:一个任务等待多个事件的触发,这种情况是比较常见的;多对多同步模型:多个任务等待多个事件的触发。
任务可以通过设置事件位来实现事件的触发和等待操作。 FreeRTOS 的事件仅用于同步,不提供数据传输功能。
特点:
- 事件只与任务相关联,事件相互独立,一个 32 位的事件集合(EventBits_t 类型的变量, 实际可用与表示事件的只有 24 位),用于标识该任务发生的事件类型,其中每一位表示一种事件类型(0 表示该事件类型未发生、 1 表示该事件类型已经发生),一共 24 种事件类型。
- 事件仅用于同步,不提供数据传输功能。
- 事件无排队性,即多次向任务设置同一事件(如果任务还未来得及读走), 等效于只设置一次。
- 允许多个任务对同一事件进行读写操作。
- 支持事件等待超时机制。
每个事件获取的时候,用户可以选择感兴趣的事件,并且选择读取事件信息标记,它有三个属性,分别是逻辑与,逻辑或以及是否清除标记。当任务等待事件同步时,可以通过任务感兴趣的事件位和事件信息标记来判断当前接收的事件是否满足要求,如果满足则说明任务等待到对应的事件,系统将唤醒等待的任务;否则,任务会根据用户指定的阻塞超时时间继续等待下去
20.2 事件的应用场景
用事件来做标志位,判断某些事件是否发生了,然后根据结果做处理。
为什么不用全局变量来做标记?需要考虑的问题如下:
- 如何对全局变量进行保护呢, 如何处理多任务同时对它进行访问?
- 如何让内核对事件进行有效管理呢?使用全局变量的话,就需要在任务中轮询查看事件是否发送,这简直就是在浪费 CPU 资源啊,还有等待超时机制,使用全局变量的话需要用户自己去实现。
因此,在挫折系统中,使用操作系统给的通信机制就好,简单方便。
在某些场合,可能需要多个时间发生了才能进行下一步操作,比如一些危险机器的启动,需要检查各项指标,当指标不达标的时候,无法启动,但是检查各个指标的时候,不能一下子检测完毕啊,所以,需要事件来做统一的等待,当所有的事件都完成了,那么机器才允许启动,这只是事件的其中一个应用。 <br /> <br />事件在一定程度上可以代替信号量。但是事件可以用于一对多,多对多的场景。信号量只能识别单一的操作。<br />任务可以根据感兴趣的事件进行关注,并根据其结果进行操作。
20.3 事件的运行机制
接收事件时,可以根据感兴趣的参事件类型接收事件的单个或者多个事件类型。事件接收成功后,必须使用 xClearOnExit 选项来清除已接收到的事件类型,否则不会清除已接收到的事件。这样需要用户显示清除事件位。用户可以自定义通过传入参数xWaitForAllBits 选择读取模式,是等待所有感兴趣的事件还是等待感兴趣的任意一个事件。
设置事件时,对指定事件写入指定的事件类型,设置事件集合的对应事件位为 1,可以一次同时写多个事件类型, 设置事件成功可能会触发任务调度。
清除事件时,根据入参数事件句柄和待清除的事件类型,对事件对应位进行清 0 操作。
事件不与任务相关联,事件相互独立,一个 32 位的变量(事件集合,实际用于表示事件的只有 24 位),用于标识该任务发生的事件类型,其中每一位表示一种事件类型(0 表示该事件类型未发生、 1 表示该事件类型已经发生)。
事件唤醒机制,当任务因为等待某个或者多个事件发生而进入阻塞态,当事件发生的时候会被唤醒。