【RT-Thread】事件集

rtthread 事件集 学习笔记

概述

学校组织秋游,组长在等待:
  • 张三:我到了
  • 李四:我到了
  • 王五:我到了
  • 组长说:好,大家都到齐了,出发!

秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的。

在这个日常生活场景中:
  • 出发:要等待这 3 个人都到齐,他们是""的关系
  • 交报告:只需等待这 3 人中的任何一个,他们是""的关系
RT-Thread 中,可以使用事件集 (event group) 来解决这些问题。

特性与操作

事件集可以简单地认为就是一个整数:
  • 每一位表示一个事件
  • 每一位事件的含义由程序员决定,比如:Bit0 表示用来串口是否就绪,Bit1 表示按键是否被按下
  • 这些位,值为 1 表示事件发生了,值为 0 表示事件没发生
  • 一个或多个线程、ISR 都可以去写这些位;一个或多个线程、ISR 都可以去读这些位
  • 可以等待某些位中的任意一个,也可以等待多位

每个线程都有一个 rt_thread 结构体,它里面有如下 2 个成员:

struct rt_thread
{
 ......
##if defined(RT_USING_EVENT)
 /* thread event */
 rt_uint32_t event_set;
 rt_uint8_t event_info;
##endif
 ......
}

 

这两个成员的作用如下:
  • event_set:想等待哪些事件?
  1. 可以设置对应的位,比如设置为(1<<30) | (1<<0)表示等待事件 0、事件 30
  2. 那么,它想等待事件 0、事件 30 都发生呢,还是只要事件 0、事件 30 任意一个发生即可?
  3. 需要使用 event_info 进一步描述
  • event_info :有 3 种取值
  1. RT_EVENT_FLAG_AND:逻辑与,比如事件 0、事件 30 都发生时,才满足它 的期待
  2. RT_EVENT_FLAG_OR:逻辑或,比如事件 0、事件 30 发生了任何一个,都满足它的期待
  3. RT_EVENT_FLAG_CLEAR:等到期待的事件后,是否清除事件
事件集和队列、信号量等不太一样,主要集中在 2 个地方:
  • 唤醒谁?
  1. 队列、信号量:事件发生时,只会唤醒一个线程
  2. 事件集:事件发生时,会唤醒所有符号条件的线程,简单地说它有"广播"的 作用
  • 是否清除事件?
  1. 队列、信号量:是消耗型的资源,队列的数据被读走就没了;信号量被获取后就减少了
  2. 事件集:被唤醒的线程有两个选择,可以让事件保留不动,也可以清除事件

事件集的常规操作如下:

  • 先创建事件集
  • 线程 C D 等待事件:
  1. 等待什么事件?可以等待某一位、某些位中的任意一个,也可以等待多位。简单地说就是""""的关系。
  2. 得到事件时,要不要清除?可选择清除、不清除。
  • 线程 A B 产生事件:设置事件集里的某一位、某些位

事件集函数

 

使用事件集之前,要先创建,得到一个句柄;使用事件集时,要使用句柄来表明使用
哪个事件集。
事件集的创建有两种方法:动态分配内存、静态分配内存,
  • 动态分配内存:rt_event_create,从对象管理器中分配一个 event 对象,并初始化这个对象
  • 静态分配内存:rt_event_init,事件集在编译时由编译器分配
rt_event_create() 函数原型如下:
rt_event_t rt_event_create(const char* name, rt_uint8_t flag);
参数
说明
name
事件集名称
flag
事件集标志,可选: RT_IPC_FLAG_FIFO RT_IPC_FLAG_PRIO
返回值
事件集句柄:成功,返回句柄,以后使用句柄来操作事件集
RT_NULL :失败

rt_event_init() 函数原型如下:
rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag);
参数
说明
mutex
事件集对象的句柄
name
事件集名称
flag
事件集标志,可选: RT_IPC_FLAG_FIFO RT_IPC_FLAG_PRIO
返回值
RT_EOK :成功

删除/脱离

不再使用一个事件集时:
  • 删除它:rt_event_delete(),只能删除使用 rt_event_create()创建的事件集
  • 脱离它:rt_event_detach(),只能脱离使用 rt_event_init()初始化的事件集
删除事件集的函数为 rt_event_delete() ,它会释放内存。原型如下:
rt_err_t rt_event_delete(rt_event_t event);
删除事件集时,如果有线程在等待该事件集,则内核会先唤醒这些线程(线程返回值是 - RT_ERROR ),然后再释放事件集使用的内存,最后删除事件集对象。
脱离事件集,就是将事件集对象被从内核对象管理器中脱离。原型如下:
rt_err_t rt_event_detach(rt_event_t event);
脱离事件集时,如果有线程在等待该事件集,则内核会先唤醒这些线程(线程返回值是 - RT_ERROR )。

发送/接收事件

RT-Thread 提供发送事件和接收事件函数:
  • rt_event_send() 发送一个或多个事件
  • rt_event_recv() 接收事件,最多同时接收 32 个事件
发送事件的函数 rt_event_send() 原型如下:
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);
使用 rt_event_send() 函数发送事件,也就是设置事件,设置哪些事件?参数 set 的每一位表示一个事件。
该函数设置事件后,会遍历等待此事件的线程,如果满足了线程期待的事件,则唤醒该线程。
参数
说明
event
事件集对象的句柄
set
发送哪些事件
返回值
RT_EOK :获取互斥量成功

接收事件的函数 rt_event_recv() 原型如下:
rt_err_t rt_event_recv(rt_event_t event,rt_uint32_t set,rt_uint8_t option,
                        rt_int32_t timeout,rt_uint32_t* recved);
使用 rt_event_recv() 函数来接收事件,通过参数 set 和参数 option 来判断接收事件是否已经发生:
set :想接收哪些事件
option :想接收这些事件里的所有事件还是任意一个事件?成功后要不要清除事件?
如果期待的事件没有发生,则挂起线程,直到事件发生或者超时。如果超时,线程退出返回-RT_ETIMEOUT
如果期待的事件已经发生,根据参数 option 是否设置有 RT_EVENT_FLAG_CLEAR 来决定是否重置事件的相应标志位。

参数
说明
event
事件集对象的句柄
set
期待哪些事件
option

                                        接收选项:

RT_EVENT_FLAG_OR :逻辑或
RT_EVENT_FLAG_AND:逻辑与
RT_EVENT_FLAG_CLEAR:清除重置
timeout
指定超时时间
recved
指向接收到的事件
返回值
RT_EOK :接收成功
RT_ETIMEOUT :接收超时
RT_ERROR :接收错误

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一叶舞澎湃

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

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

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

打赏作者

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

抵扣说明:

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

余额充值