1、事件的基本概念:
事件是一种实现线程间通信的机制,主要用于实现线程间的同步,但事件通信只能是事件类型的 通信,无数据传输。与信号量不同的是,它可以实现一对多,多对多的同步。
2、事件的应用场景:
RT-Thread 的事件用于事件类型的通讯,无数据传输,也就是说,我们可以用事件来做标志位,判 断某些事件是否发生了,然后根据结果做处理。
3、事件控制块:
1 struct rt_event {
2 struct rt_ipc_object parent;
3
4 rt_uint32_t set; /* 事件标志位 */
5 };
6 typedef struct rt_event *rt_event_t; /* rt_event_t 是指向事件结构体的指针 */
4、 事件函数接口讲解
(1)事件创建函数 rt_event_create()
事件创建函数 rt_event_create() 源码:
1 rt_event_t rt_event_create(const char *name, rt_uint8_t flag)
2 {
3 rt_event_t event;
4
5 RT_DEBUG_NOT_IN_INTERRUPT;
6
7 /* 分配对象 */
8 event = (rt_event_t)rt_object_allocate(RT_Object_Class_Event, name);
9 if (event == RT_NULL)
10 return event;
11
12 /* 设置阻塞唤醒的模式 */
13 event->parent.parent.flag = flag;
14
15 /* 初始化事件对象 */
16 rt_ipc_object_init(&(event->parent));
17
18 /* 事件集合清零 */
19 event->set = 0;
20
21 return event;
22 }
23 RTM_EXPORT(rt_event_create);
(2)事件删除函数 rt_event_delete()
事件删除函数 rt_event_delete() 源码:
1 rt_err_t rt_event_delete(rt_event_t event)
2 {
3 /* 事件句柄检查 */
4 RT_ASSERT(event != RT_NULL);
5
6 RT_DEBUG_NOT_IN_INTERRUPT;
7
8 /* 恢复所有阻塞在此事件的线程 */
9 rt_ipc_list_resume_all(&(event->parent.suspend_thread));
10
11 /* 删除事件对象 */
12 rt_object_delete(&(event->parent.parent));
13
14 return RT_EOK;
15 }
16 RTM_EXPORT(rt_event_delete);
(3)事件发送函数 rt_event_send()
事件发送函数 rt_event_send() 源码:
1 rt_err_t rt_event_send(rt_event_t event,
2 rt_uint32_t set)
3 {
4 struct rt_list_node *n;
5 struct rt_thread *thread;
6 register rt_ubase_t level;
7 register rt_base_t status;
8 rt_bool_t need_schedule;
9
10 /* 事件对象检查 */
11 RT_ASSERT(event != RT_NULL);
12 if (set == 0)
13 return -RT_ERROR;
14
15 need_schedule = RT_FALSE;
16 RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(event->parent.parent)));
17
18 /* 关中断 */
19 level = rt_hw_interrupt_disable();
20
21 /* 设置事件 */
22 event->set |= set;
24 if (!rt_list_isempty(&event->parent.suspend_thread)) {
25 /* 搜索线程列表以恢复线程 */
26 n = event->parent.suspend_thread.next;
27 while (n != &(event->parent.suspend_thread)) {
28 /* 找到要恢复的线程 */
29 thread = rt_list_entry(n, struct rt_thread, tlist);
30
31 status = -RT_ERROR;
32 if (thread->event_info & RT_EVENT_FLAG_AND) {
33 if ((thread->event_set & event->set)
34 == thread->event_set) {
35 /* 收到了一个 AND */
36 status = RT_EOK;
37 }
38 } else if (thread->event_info & RT_EVENT_FLAG_OR) {
39 if (thread->event_set & event->set) {
40 /* 保存收到的事件集 */
41 thread->event_set = thread->event_set & event->set;
42
43 /* 收到一个 OR */
44 status = RT_EOK;
45 }
46 }
47
48 /* 将节点移动到下一个节点 */
49 n = n->next;
50
51 /* 条件满足,恢复线程 */
52 if (status == RT_EOK) {
53 /* 清除事件标志位 */
54 if (thread->event_info & RT_EVENT_FLAG_CLEAR)
55 event->set &= ~thread->event_set;
56
57 /* 恢复线程 */
58 rt_thread_resume(thread);
59
60 /* 需要进行线程调度 */
61 need_schedule = RT_TRUE;
62 }
63 }
64 }
65
66 /* 开中断 */
67 rt_hw_interrupt_enable(level);
68
69 /* 发起一次线程调度 */
70 if (need_schedule == RT_TRUE)
71 rt_schedule();
72
73 return RT_EOK;
74 }
75 RTM_EXPORT(rt_event_send);
(4)事件接受函数 rt_event_recv()
事件接受函数 rt_event_recv() 源码:
1 rt_err_t rt_event_recv(rt_event_t event,
2 rt_uint32_t set,
3 rt_uint8_t option,
4 rt_int32_t timeout,
5 rt_uint32_t *recved)
6 {
7 struct rt_thread *thread;
8 register rt_ubase_t level;
9 register rt_base_t status;
10
11 RT_DEBUG_IN_THREAD_CONTEXT;
12
13 /* 检查事件句柄 */
14 RT_ASSERT(event != RT_NULL);
15 if (set == 0)
16 return -RT_ERROR;
17
18 /* 初始化状态 */
19 status = -RT_ERROR;
20 /* 获取当前线程 */
21 thread = rt_thread_self();
22 /* 重置线程错误码 */
23 thread->error = RT_EOK;
24
25 RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(event->parent.parent)));
26
27 /* 关中断 */
28 level = rt_hw_interrupt_disable();
29
30 /* 检查事件接收选项& 检查事件集合 */
31 if (option & RT_EVENT_FLAG_AND) {
32 if ((event->set & set) == set)
33 status = RT_EOK;
34 } else if (option & RT_EVENT_FLAG_OR) {
35 if (event->set & set)
36 status = RT_EOK;
37 } else {
38 /* 应设置 RT_EVENT_FLAG_AND 或 RT_EVENT_FLAG_OR */
39 RT_ASSERT(0);
40 }
41
42 if (status == RT_EOK) {
43 /* 返回接收的事件 */
44 if (recved)
45 *recved = (event->set & set);
46
47 /* 接收事件清除 */
48 if (option & RT_EVENT_FLAG_CLEAR)
49 event->set &= ~set;
50 } else if (timeout == 0) {
51 /* 不等待 */
52 thread->error = -RT_ETIMEOUT;
53 } else {
54 /* 设置线程事件信息 */
55 thread->event_set = set;
56 thread->event_info = option;
57
58 /* 将线程添加到阻塞列表中 */
59 rt_ipc_list_suspend(&(event->parent.suspend_thread),
60 thread,
61 event->parent.parent.flag);
62
63 /* 如果有等待超时,则启动线程计时器 */
64 if (timeout > 0) {
65 /* 重置线程超时时间并且启动定时器 */
66 rt_timer_control(&(thread->thread_timer),
67 RT_TIMER_CTRL_SET_TIME,
68 &timeout);
69 rt_timer_start(&(thread->thread_timer));
70 }
71
72 /* 开中断 */
73 rt_hw_interrupt_enable(level);
74
75 /* 发起一次线程调度 */
76 rt_schedule(); (18)
77
78 if (thread->error != RT_EOK) {
79 /* 返回错误代码 */
80 return thread->error;
81 }
82
83 /* 接收一个事件,失能中断 */
84 level = rt_hw_interrupt_disable();
85
86 /* 返回接收到的事件 */
87 if (recved)
88 *recved = thread->event_set;
89 }
90
91 /* 开中断 */
92 rt_hw_interrupt_enable(level);
93
94 RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(event->parent.parent)));
95
96 return thread->error;
97 }
98 RTM_EXPORT(rt_event_recv);