文章目录
事件集
一个事件集可以包含多个事件,利用事件集可以完成一对多,多对多的线程间同步。
例子:出游这一事件,组织者在等人(事件)
张三:到了
李四:到了
王五:到了
组织者表示都到了,出发
事件集工作机制
事件集主要用于线程间的同步,与信号量不同,它的特点是可以实现一对多,多对多的同步。
一个线程对多个事件
:任意一个事件唤醒线程,或多个事件唤醒线程
多个线程对多个事件
:多个事件可以用32位无符号整型变量表示(和优先级一样),一位数表示一个事件(一位数表示一个优先级),线程需要的位数(事件)通过“逻辑与” 或“逻辑或”计算出0或1(优先级取最低位),事件的 “逻辑或” 也称为是独立型同步,指的是线程与任何事件之一发生同步;事件 “逻辑与” 也称为是关联型同步,指的是线程与若干事件都发生同步。
RT-Thread 定义的事件集有以下特点:
1)事件只与线程相关,事件间相互独立:每个线程可拥有 32 个事件标志,采用一个 32 bit 无符号整型数进行记录,每一个 bit 代表一个事件;
2)事件仅用于同步,不提供数据传输功能;
3)事件无排队性,即多次向线程发送同一事件 (如果线程还未来得及读走),其效果等同于只发送一次。
在 RT-Thread 中,每个线程都拥有一个事件信息标记,它有三个属性,分别是 RT_EVENT_FLAG_AND(逻辑与),RT_EVENT_FLAG_OR(逻辑或)以及 RT_EVENT_FLAG_CLEAR(清除标记)。当线程等待事件同步时,可以通过 32 个事件标志和这个事件信息标记来判断当前接收的事件是否满足同步条件。
线程中事件设置
下图中事件集为上图event_set成员
如图所示,一个事件集有32位,其中标志位第一位和第三十位被置1,而线程1只要关注第一位和第三十位,
event_info事件信息标志位
RT_EVENT_FLAG_AND(逻辑与):线程 1 只有在事件 1 和事件 30 都发生以后才会被触发唤醒
RT_EVENT_FLAG_OR(逻辑或):事件 1 或事件 30 中的任意一个发生都会触发唤醒线程 1
RT_EVENT_FLAG_CLEAR(清除标记):线程 1 唤醒后将主动把事件 1 和事件 30 清为零,否则事件标志将依然存在(即置 1)
事件集控制块
struct rt_event
{
struct rt_ipc_object parent; /**< inherit from ipc_object */
rt_uint32_t set; /**< 事件集设置位 */
};
typedef struct rt_event *rt_event_t;
#endif
ipc对象继承
struct rt_ipc_object
{
struct rt_object parent; //name、type、flag
rt_list_t suspend_thread; //等待事件线程,看出那些线程和事件集相关
};
事件操作
操作和信号量一样
对一个事件集的操作包含:初始化 / 脱离事件集、创建 / 删除事件集、发送事件、接收事件。
代码顺序为内核中ipc.c顺序,即编写顺序
初始化 / 脱离事件集
初始化
静态事件集对象的内存是在系统编译时由编译器分配的,一般放于读写数据段或未初始化数据段中。在使用静态事件集对象前,需要先行对它进行初始化操作。
rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag)
{
/* parameter check */
RT_ASSERT(event != RT_NULL);//核查是否为事件集
/* init object */
rt_object_init(&(event->parent.parent), RT_Object_Class_Event, name);//对象设置为事件集对象,并设置名字
/* set parent flag */
event->parent.parent.flag = flag;//设置对象标志位
/* init ipc object */
rt_ipc_object_init(&(event->parent));//ipc对象初始化,对象中有个链表进行初始化
/* init event */
event->set = 0;//无事件发生
return RT_EOK;
}
RTM_EXPORT(rt_event_init);
脱离
系统不再使用 rt_event_init() 初始化的事件集对象时,通过脱离事件集对象控制块来释放系统资源。脱离事件集是将事件集对象从内核对象管理器中脱离。
rt_err_t rt_event_detach(rt_event_t event)
{
/* parameter check */
RT_ASSERT(event != RT_NULL);//是否为事件
RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);//对象是否为事件
RT_ASSERT(rt_object_is_systemobject(&event->parent.parent));//是否为静态对象
/* resume all suspended thread */
r