事件集合:
事件集主要用于线程间的同步,与信号量不同,它的特点是可以实现一对一,一对多,多对多的同步。即一个线程与多个事件的关系可设置为:其中任意一个事件唤醒线程,或几个事件都到达后才唤醒线程进行后续的处理;同样,事件也可以是多个线程同步多个事件。
在RT-Thread中用一个 32 位无符号整型变量来表示,变量的每一位代表一个事件,也就是说RT-Thread默认是可以设置32个事件。
操作原理
线程通过 “逻辑与” 或 “逻辑或” 将一个或多个事件关联起来,形成事件组合。
独立型同步
事件的 “逻辑或” 也称为是独立型同步,指的是线程与任何事件之一发生同步。
关联型同步
事件 “逻辑与”也称为是关联型同步,指的是线程与若干事件都发生同步。
特点:
1)事件只与线程相关,事件间相互独立:每个线程可拥有 32 个事件标志,采用一个 32 bit 无符号整型数进行记录,每一个 bit 代表一个事件;
2)事件仅用于同步,不提供数据传输功能;传输数据用邮箱机制
3)事件无排队性,即多次向线程发送同一事件 (如果线程还未来得及读走),其效果等同于只发送一次。
在 RT-Thread 中,每个线程都拥有一个事件信息标记,它有三个属性,分别是 RT_EVENT_FLAG_AND(逻
辑与),RT_EVENT_FLAG_OR(逻辑或)以及 RT_EVENT_FLAG_CLEAR(清除标记)。当线程等待
事件同步时,可以通过 32 个事件标志和这个事件信息标记来判断当前接收的事件是否满足同步条件。
事件集管理数据结构
/*
* event structure
*/
struct rt_event
{
struct rt_ipc_object parent; /**< inherit from ipc_object */
rt_uint32_t set; /**< event set */
};
typedef struct rt_event *rt_event_t;
事件集定义
struct rt_event static_event; /*静态事件集*/
rt_event_t dynamic_event; /*动态事件集*/
初始化与脱离-同信号量和互斥锁类似,主要针对静态定义
/**
* 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 使用方式 RT_IPC_FLAG_FIFO/RT_IPC_FLAG_RRIO
*
* @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)
/**
* This function will detach an event object from resource management
*
* @param event the event object
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_event_detach(rt_event_t event)
创建与删除-同信号量和互斥锁类似,主要针对动态定义
/**
* This function will create an event object from system resource
*
* @param name the name of event
* @param flag the flag of event
*
* @return the created event, RT_NULL on error happen
*/
rt_event_t rt_event_create(const char *name, rt_uint8_t flag)
/**
* This function will delete an event object and release the memory
*
* @param event the event object
*
* @return the error code
*/
rt_err_t rt_event_delete(rt_event_t event)
发送事件
/**
* This function will send an event to the event object, if there are threads
* suspended on event object, it will be waked up.
*
* @param event the event object
* @param set the event set 这里保存的就是预先定义的事件位
*
* @return the error code
*/
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
接收事件
/**
* This function will receive an event from event object, if the event is
* unavailable, the thread shall wait for a specified time.
*
* @param event the fast event object
* @param set the interested event set 感兴趣的事件集
* @param option the receive option, either
* RT_EVENT_FLAG_AND 表示检测多个事件同时发生
* RT_EVENT_FLAG_OR 表示检测其中一个事件发生
* RT_EVENT_FLAG_CLEAR 系统是否重置事件的相应标志位
* @param timeout the waiting time
* @param recved the received event, if you don't care, RT_NULL can be set.
*
* @return the error code
*/
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)
参考官网例程
/*
*
* 程序会初始化2个线程及初始化一个静态事件对象
* 一个线程等待于事件对象上,以接收事件;
* 一个线程发送事件 (事件3/事件5)
*/
#include <rtthread.h>
#define THREAD_PRIORITY 9
#define THREAD_TIMESLICE 5
#define EVENT_FLAG3 (1 << 3)
#define EVENT_FLAG5 (1 << 5)
/* 事件控制块 */
static struct rt_event event;
ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;
/* 线程1入口函数 */
static void thread1_recv_event(void *param)
{
rt_uint32_t e;
/* 第一次接收事件,事件3或事件5任意一个可以触发线程1,接收完后清除事件标志 */
if (rt_event_recv(&event, (EVENT_FLAG3 | EVENT_FLAG5),
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &e) == RT_EOK)
{
rt_kprintf("thread1: OR recv event 0x%x\n", e);
}
rt_kprintf("thread1: delay 1s to prepare the second event\n");
rt_thread_mdelay(1000);
/* 第二次接收事件,事件3和事件5均发生时才可以触发线程1,接收完后清除事件标志 */
if (rt_event_recv(&event, (EVENT_FLAG3 | EVENT_FLAG5),
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &e) == RT_EOK)
{
rt_kprintf("thread1: AND recv event 0x%x\n", e);
}
rt_kprintf("thread1 leave.\n");
}
ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
/* 线程2入口 */
static void thread2_send_event(void *param)
{
rt_kprintf("thread2: send event3\n");
rt_event_send(&event, EVENT_FLAG3);
rt_thread_mdelay(200);
rt_kprintf("thread2: send event5\n");
rt_event_send(&event, EVENT_FLAG5);
rt_thread_mdelay(200);
rt_kprintf("thread2: send event3\n");
rt_event_send(&event, EVENT_FLAG3);
rt_kprintf("thread2 leave.\n");
}
int event_sample(void)
{
rt_err_t result;
/* 初始化事件对象 */
result = rt_event_init(&event, "event", RT_IPC_FLAG_FIFO);
if (result != RT_EOK)
{
rt_kprintf("init event failed.\n");
return -1;
}
rt_thread_init(&thread1,
"thread1",
thread1_recv_event,
RT_NULL,
&thread1_stack[0],
sizeof(thread1_stack),
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
rt_thread_startup(&thread1);
rt_thread_init(&thread2,
"thread2",
thread2_send_event,
RT_NULL,
&thread2_stack[0],
sizeof(thread2_stack),
THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(&thread2);
return 0;
}