物联网操作系统AliOS Things探索与实践
上QQ阅读APP看书,第一时间看更新

2.10 事件机制(event)

2.10.1 概念

事件机制与信号量机制比较类似,也可以用来在多个task中实现资源、业务流的同步机制。

(1)事件机制与信号量机制类似的地方有:

①事件也有创建/删除、获取/释放机制;

②在获取事件不满足条件时,当前task也会被pend到事件上,当事件满足时继续运行。

(2)事件机制与信号量机制不同的地方有:

①事件机制比信号量机制更灵活;

②事件机制可以一次性等待多个条件同时满足,或者其中任意标志位满足。

2.10.2 event的定义

下面是一个简化版的event的定义,标志位flags是event的核心元素,flags有32位,每一位都可以表示一个独立事件,这样一个event可以同时等待32个独立事件的发生或者其中任意一个事件的发生。

    typedef struct {
        blk_obj_t blk_obj;
        uint32_t  flags;
    }kevent_t;

示例1:task A需要等待5个独立事件都满足条件后再执行任务,这5个独立事件由另外5个独立外部事件驱动,且由5个独立的中断源来释放。如果没有事件机制,一个可能的方案是利用信号量的方式来实现,但业务逻辑会比较复杂,而利用event机制就方便多了,task A只需要等待一个event,然后5个中断分别独立设置event-->flags中独立的5个标志位,当5个标志位都满足时,task A将立即执行既定任务。

示例2:task B需要等待5个独立事件中的任何一个事件发生后再执行任务,这5个独立事件由另外5个独立外部事件驱动,且由5个独立的中断源来释放。task B只需要等待一个event,然后5个中断分别独立设置event->flags中独立的5个标志位,其中任何一个标志位满足时,task B将立即执行既定任务。任意标志位满足即可,还是所有标志位都需要满足,由事件获取函数的参数决定,参见下面事件的获取/释放部分。

2.10.3 事件的创建/删除

(1)静态创建:kstat_t krhino_event_create(kevent_t *event, const name_t *name, uint32_t flags),其中,event结构体的内存空间已事先分配好。

(2)动态创建:kstat_t krhino_event_dyn_create(kevent_t **event, const name_t *name, uint32_t flags),其中,event结构体的内存空间在调用时分配。

(3)静态删除:kstat_t krhino_event_del(kevent_t *event)。

(4)动态删除:kstat_t krhino_event_dyn_del(kevent_t *event)。

【注意】在删除event时,如果有task还pend在此event上时,这些task将会从此event上脱离,从而导致task行为类似event的条件被满足的样子,但与event真实条件满足是两个业务逻辑,且当task再次获取此event时,因为event的不存在而导致获取失败。所以,在删除event时需要仔细分析删除event带来的逻辑变化。

2.10.4 事件的获取/释放

(1)获取事件:kstat_t krhino_event_get(kevent_t *event, uint32_t flags, uint8_t opt, uint32_t *actl_flags, tick_t ticks),其中,参数opt对应有以下四种选项:

①RHINO_AND期望所有flags bit都为1

②RHINO_AND_CLEAR期望所有flags bit都为1,且清除event的内部flags

③RHINO_OR期望任意flags bit为1就好

④RHINO_OR_CLEAR期望任意flags bit为1就好,且清除event的内部flags

(2)释放event:kstat_t krhino_event_set(kevent_t *event, uint32_t flags, uint8_t opt),其中,参数opt与获取不同,这里只有两个选项:

①RHINO_AND把期望设置的flags与内部event->flags相与完成设置

②RHINO_OR把期望设置的flags与内部event->flags相或完成设置

【注意】在使用RHINO_AND方式来设置flags时,并不会增加event-->flags的有效位数。

【注意】krhino_event_set()的执行上下文可以是task或者中断上下文,krhino_event_get()的执行上下文只能是task,而不能中断上下文。