事件标志
Categories:
2 分钟阅读
概述
当系统需要处理很多事件,如果每个事件都绑定一个特定的条件量, 每个条件量又由一个线程进行等待处理,会导致系统需要大量内存来创建条件量和线程。
事件标志使用位图来管理一组事件,位图中的每个位代表一个事件, 当一个或多个事件状态发生变化时,事件对应的位也会发生变化,并唤醒正在等待的线程。 线程唤醒后,就可从事件位图中获取事件的状态。
- 线程可以等待位图中的事件位被置 1 ,也可以等待事件位被清 0 。
- 线程可以等待位图中的事件位同时被置 1 (事件与事件之间是逻辑 与 的关系),也可以等待其中任意一个位被置 1 (事件与事件之间是逻辑 或 的关系)。
- 线程可以等待位图中的事件位同时被清 0 (事件与事件之间是逻辑 与 的关系),也可以等待其中任意一个位被清 0 (事件与事件之间是逻辑 或 的关系)。
- 线程可以选择是否 消费 事件。 消费 事件是指,当事件到来,线程被唤醒时,可以选择是否 清除 事件。
- 线程可以等待事件标志位发生 翻转 , 翻转 是指事件标志位由 1 变为 0 ,或由 0 变为 1 。
事件标志对象与对象描述符描述符
事件标志对象是 XWOS对象 struct xwos_object
的派生类 。
类似的,事件标志对象也用 事件标志对象描述符 xwos_flg_d
来解决有效性和身份合法性的问题。
事件标志对象描述符由 事件标志对象的指针 和 标签 组成:
typedef struct {
struct xwos_flg * flg; /**< 事件标志对象的指针 */
xwsq_t tik; /**< 标签 */
} xwos_flg_d;
通过对象描述符引用对象时,首先检测 obj->magic
的值,是否为 0x58574F53U
,由此可确定指针 obj
指向一个有效的 XWOS的对象 。
然后对比标签 obj->tik
和 tik
是否相等,由此可以确定对象的 身份 。
因为对象的 tik
是全局唯一的,当对象被释放后,它的 tik
会被析构函数析构为 0 。
当内存地址被重新构建为新的对象,那么它的 tik
一定与对象描述符的 tik
不一致。
事件标志的初始化、销毁与动态创建、删除
静态初始化、销毁
- 静态初始化:
xwos_flg_init()
- 静态 是指用户预先定义线程结构体对象,这些对象在编译期由编译器分配内存。
- 销毁静态初始化的事件标志
xwos_flg_fini()
动态创建、删除
- 动态创建:
xwos_flg_create()
- 动态 是指程序在运行时,通过内存分配函数申请内存,并在申请的内存上构造对象。
- 删除动态创建的事件标志
xwos_flg_delete()
产生事件
XWOS提供6个CAPI产生触发事件:
xwos_flg_s1m()
:同时设置多个事件标志位,可在 任意 上下文使用xwos_flg_s1i()
:设置单个事件标志位,可在 任意 上下文使用xwos_flg_c0m()
:同时清除多个事件标志位,可在 任意 上下文使用xwos_flg_c0i()
:清除单个事件标志位,可在 任意 上下文使用xwos_flg_x1m()
:同时翻转多个事件标志位,可在 任意 上下文使用xwos_flg_x1i()
:翻转单个事件标志位,可在 任意 上下文使用
这些CAPI除了会修改事件标志位图的状态,还会通过 广播 唤醒所有正在等待的线程。 然后,线程通过比对位图状态,确定事件是否已经满足触发条件。 若满足触发条件,就退出等待;若未满足触发条件,重新进入阻塞等待状态。
获取事件的状态
xwos_flg_get_num()
获取事件标志中总共有多少个事件xwos_flg_read()
直接读取事件的位图状态。此函数立即返回,不会阻塞
等待事件
xwos_flg_wait()
:等待事件,只能在 线程 上下文使用xwos_flg_wait_to()
:限时等待事件,只能在 线程 上下文使用xwos_flg_trywait()
:检查事件,可在 任意 上下文使用
触发条件
当调用等待事件的CAPI时,需要指定触发条件(参数: trigger
)。触发条件分为 电平触发 和 边沿触发 。
电平触发
电平触发 源于数字电路,是一种类比概念,是指事件位的特定的状态( 1 或 0 )所产生的触发信号,下面的触发条件均为电平触发:
XWOS_FLG_TRIGGER_SET_ALL
:所有事件位被置 1XWOS_FLG_TRIGGER_SET_ANY
:任意事件位被置 1XWOS_FLG_TRIGGER_CLR_ALL
:所有事件位被清 0XWOS_FLG_TRIGGER_CLR_ANY
:任意事件位被清 0
边沿触发
边沿触发 源于数字电路,是一种类比概念,是指事件状态发生改变( 1 变 0 或 0 变 1 )时产生的唤醒信号,下面的触发条件为边沿触发:
XWOS_FLG_TRIGGER_TGL_ALL
:所有事件位发生翻转XWOS_FLG_TRIGGER_TGL_ANY
:任意事件位发生翻转
边沿触发时,必须要有一个初始状态,就像数字电路一样:
- 当位的初始值为 0 (低电平),然后跳变到 1 (高电平)的瞬间被称为上升沿。此时触发的事件被称为上升沿触发。
- 当位的初始值为 1 (高电平),然后跳变到 0 (低电平)的瞬间被称为下降沿。此时触发的事件被称为下降沿触发。
清除事件
- 当采用 电平触发 时,需要在读取事件位图后 清除 事件标志位,否则事件会一直处于触发状态。
可以在调用CAPI时,指定参数
action
为XWOS_FLG_ACTION_CONSUMPTION
。 清除 的含义是:- 当线程等待的是位图中的事件位被置 1 , 清除 是指将这些位清 0 ;
- 当线程等待的是位图中的事件位被清 0 , 清除 是指将这些位置 1 ;
- 当采用 边沿触发 时,不需要 清除 事件的触发条件。
绑定与解绑信号选择器
可以通过 xwos_flg_bind()
将事件标志绑定到 信号选择器 上。
当等待的事件发生时,事件标志会向 信号选择器 发送一个 选择信号 。此时 信号选择器 会唤醒正在等待的线程。
绑定后的事件标志可以通过 xwos_flg_unbind()
解绑。
事件标志对象的生命周期管理
事件标志对象的基类是 XWOS对象 struct xwos_object
。
事件标志对象也有两组生命周期管理的CAPI:
-
使用 对象指针 访问生命周期管理的CAPI:需要确保调用CAPI时,对象一定是有效的,且不存在 释放-又被申请 为另一个对象的情况。
xwos_flg_grab()
:增加引用计数。xwos_flg_put()
:减少引用计数,当引用计数减少为 0 时,调用垃圾回收函数释放对象。
-
使用 对象描述符 访问生命周期管理的CAPI:用户无法确保对象一定有效或无法确保对象不会变成另一个对象时使用。
xwos_flg_acquire()
:通过对象描述符确定对象有效且合法,再增加引用计数。xwos_flg_release()
:通过对象描述符确定对象有效且合法,再减少引用计数。 当引用计数减少为 0 时,调用垃圾回收函数释放对象。