一、RTOS事件介绍
事件集也是线程间同步的机制之一,一个事件集可以包含多个事件,利用事件集可以完成一对多,多对多的线程间同步。
一个线程和多个事件的关系可设置为:其中任意一个事件唤醒 线程,或几个事件都到达后唤醒线程,多个事件集合可以用一个32bit无符号整型变量来表示,变量的每一位代表一个事件,线程通过"逻辑与"或"逻辑或"将一个或多个事件关联起来,形成事件组合。
RT-Thread 定义的事件集有以下特点:
☐ 事件只与线程相关,事件间相互独立
☐ 事件仅用于同步,不提供数据传输功能
☐ 事件无排队性,即多次向线程发送同一事件(如果线程还未来得及读走),其效果等同于只发送一次。事件集与信号量都是同步作用,都没有传输功能,它们主要区别是事件集具有条件作用,比如两个事件的与和或。信号量是它的值不为0就可以申请资源。
二、事件的使用
对一个事件集的操作包含:创建/初始化事件集、发送事件、接收事件、删除/脱离事件集。跟信号量、线程创建都是一个套路的。
2.1 创建事件比较简单,rt_event_create()第一个参数是事件名,第二个是线程的属性,RT_IPC_FLAG_FIFO就代表当前线程如果接收不到事件就会一直等待,当有事件来的时候就第一个唤醒的是最早在等待的线程,先进先出。创建一个事件集有32位可以用,你要先定义好哪个bit位来表示你的事件,如何用最低位来做事件:#define LED_EVENT (0x00000001 << 0)
,说到底其实事件就是标志位,之所以RTOS之所以这样做是为了方便维护和使用。
2.2 当静态thread1启动时候就会发送LED_EVENT事件并打印,thread2等待接收,判断event_flag是不是LED_EVENT事件,如果是就i=0去回调callback_fun()函数,这里写了复杂化用了回调函数。在很多项目工程中一般都是用一个数组把接收到的事件和对应的处理回调函数绑定的,我这里只有一个一维数组,其实用的项目里面有很多事件,对应很多处理函数,数组都是多维的。这里我简单模拟一下。
打印结果图:
#include "board.h" //头文件合集
#include <stdio.h>
#define LED_EVENT (0x00000001 << 0)
// 定义函数指针类型
typedef void (*FuncPtr)(uint32_t);
// 定义结构体
struct MyStruct
{
uint32_t event;
FuncPtr callback;
};
//回调函数
void callback_fun(uint32_t event)
{
rt_kprintf("RECV LED_EVENT:%d\r\n",event);
}
//定义结构体数组并初始化
struct MyStruct callbacks[] = {
{LED_EVENT, callback_fun}
};
struct rt_thread thread1;
struct rt_thread thread2;
rt_uint8_t thread1_stack[512]={0};
rt_uint8_t thread2_stack[512]={0};
static rt_event_t test_event = RT_NULL;
static void thread1_callback(void *parameter)
{
rt_err_t result;
while(1)
{
//发送事件
result = rt_event_send(test_event,LED_EVENT);
if(result == RT_EOK)
{
rt_kprintf("SEND LED_EVENT\r\n");
rt_thread_delay(300);//延时300ms,让thread2可以去运行
}
}
}
static void thread2_callback(void *parameter)
{
uint32_t event_flag=0;
int i;
while(1)
{ //等待接收事件标志
rt_event_recv(test_event,
LED_EVENT,
RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER,
&event_flag);
if(event_flag == LED_EVENT)
{
i = 0;
}
callbacks[i].callback(callbacks[i].event);
rt_thread_delay(300);//延时300ms,让thread1可以去运行
}
}
int main(void)
{
//创建一个事件
test_event = rt_event_create("test_event",RT_IPC_FLAG_FIFO);
rt_thread_init(&thread1,
"thread1",
thread1_callback,
NULL,
&thread1_stack[0],
sizeof(thread1_stack),
7,
5);
/*5是时间片,作用是当有相同优先级的线程时,最大执行时间是5 tick
如果线程毁掉函数执行时间少于5 tick,也会提前返回,切换带到下一个线程
如果5 tick还没执行完也会切换到下一个线程 */
rt_thread_init(&thread2,
"thread2",
thread2_callback,
RT_NULL,
&thread2_stack[0],
sizeof(thread2_stack),
8,
5);
//开启两个线程
rt_thread_startup(&thread1);
rt_thread_startup(&thread2);
return 0;
}