1 前言
事件主要用于线程间的同步,与信号量不同,它的特点是可以实现一对多,多对多的同步。即一个线程可等待多个事件的触发:可以是其中任一一个事件进行触发唤醒线程进行事件的处理操作;也可以是几个事件都到达后才触发唤醒线程进行后续的处理。同样,事件也可以是多个线程同步多个事件。这种多个事件的集合可以用一个32位无符号整型变量来表示,变量中的一位代表一个事件,线程通过“逻辑与”或“逻辑或”与一个或多个事件建立关联形成一个事件集。
事件的“逻辑或”也称为是独立型同步,指的是线程与任何事件之一发生同步;事件“逻辑与”也称为是关联型同步,指的是线程与若干事件都发生同步。
RT-Thread定义的事件有以下特点:
1. 事件只与线程相关,事件间相互独立:RT-Thread 定义的每个线程拥有32个事件标志,用一个32-bit无符号整型数记录,每一个bit代表一个事件。若干个事件构成一个事件集;
2. 事件仅用于同步,不提供数据传输功能;
3. 事件无排队性,即多次向线程发送同一事件(如果线程还未来得及读走),其效果等同于只发送一次。
在RT-Thread实现中, 每个线程还拥有一个事件信息标记(见:http://blog.csdn.net/flydream0/article/details/8584362 一文的第1章线程控制块的说明), 它有三个属性,分别是RT_EVENT_FLAG_AND (逻辑与), RT_EVENT_FLAG_OR (逻辑或) 以及RT_EVENT_FLAG_CLEAR (清除标记)。当线程等待事件同步时, 就可以通过32个事件标志和一个事件信息标记来判断当前接收的事件是否满足同步条件。
如上图所示,线程1的事件标志中第三位和第十位被置位,如果事件信息标记位设为逻辑与,则表示线程1只有在事件3和事件10都发生以后才会被触发唤醒,如果事件信息标记位设为逻辑或,则事件3或事件10中的任意一个发生都会触发唤醒线程1。如果信息标记同时设置了清除标记位,则发生的事件会导致线程1的相应事件标志位被重新置位为零。
2 事件控制块
事件的控件块如下定义:
/*
* event structure
*/
struct rt_event
{
struct rt_ipc_object parent; /**< inherit from ipc_object *///从IPC对象派生
rt_uint32_t set; /**< event set *///保存接收到的事件集
};
typedef struct rt_event *rt_event_t;
由上源码可知,事件的控制块也是从IPC对象派生。
3 接口实现源码分析
3.1 初始化事件
/**
* This function will initialize an event and put it under control of resource
* management.
*
* @param event the event object
* @param name the name of event
* @param flag the flag of event
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag)
{
RT_ASSERT(event != RT_NULL);
/* init object */
rt_object_init(&(event->parent.parent), RT_Object_Class_Event, name);//初始化事件的内核对象
/* set parent fla