前言
- RT-Thread 的事件集(rt_event),常用于线程间的【同步】
- 事件集属于线程间通信(IPC),一般是多个线程或中断,发送事件给一个线程,即多对一的消息通知
事件集API
- rt_event_init : 静态初始化一个事件集(rt_event),注意这个事件集是全局变量
- rt_event_detach : 当rt_event_init初始化的事件集不再使用时,脱离掉(反初始化),事件集变量还在,只是不能直接使用。
- rt_event_create : 动态创建一个事件集,需要首先开启
RT_USING_HEAP
- rt_event_delete : 删除 rt_event_create动态创建的事件集,内存资源释放。
- rt_event_send : 发送事件,可以是单一事件或一组事件的集合。可以在线程、中断回调等环境发送
- rt_event_recv :等待接收事件,可以设置超时,或一直等待RT_WAITING_FOREVER,事件集可以与、或,只有接收条件的事件,才会接收。注意接收时,需要需要判断返回值为:
== RT_EOK
。
if (rt_event_recv(&t3_evt, 0x0F,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &_evt_set) == RT_EOK)
- rt_event_control :代码实现了一个复位事件集的命令处理,不常用。
测试例程
#include <rtthread.h>
#include <stdlib.h>
#define DBG_ENABLE
#define DBG_SECTION_NAME "event.test"
#define DBG_LEVEL DBG_LOG
#include <rtdbg.h>
static struct rt_event t1_evt; /* 静态初始化 */
static struct rt_event t2_evt;
static struct rt_event t3_evt;
#define THREAD1_STACK_SIZE 1024 /* 测试线程 */
#define THREAD1_PRIORITY 20
#define THREAD1_TIMESLICE 10
#define THREAD2_STACK_SIZE 1024
#define THREAD2_PRIORITY 20
#define THREAD2_TIMESLICE 10
#define THREAD3_STACK_SIZE 1024
#define THREAD3_PRIORITY 20
#define THREAD3_TIMESLICE 10
static rt_thread_t tid1 = RT_NULL;
static rt_thread_t tid2 = RT_NULL;
static rt_thread_t tid3 = RT_NULL;
#define FLAG_RECV_01 (1<<0) /* 测试事件 */
#define FLAG_RECV_02 (1<<1)
#define FLAG_RECV_03 (1<<2)
/* 事件集初始化 */
static void event_init(void)
{
rt_err_t result;
/* 初始化事件集 */
result = rt_event_init(&t1_evt, "event1", RT_IPC_FLAG_FIFO);
if (result != RT_EOK)
{
LOG_D("init thread1 event failed.\n");
return;
}
result = rt_event_init(&t2_evt, "event2", RT_IPC_FLAG_FIFO);
if (result != RT_EOK)
{
LOG_D("init thread2 message queue failed.\n");
return;
}
result = rt_event_init(&t3_evt, "event3", RT_IPC_FLAG_FIFO);
if (result != RT_EOK)
{
LOG_D("init thread3 message queue failed.\n");
return;
}
}
/* 事件集接收测试线程 */
static void thread1_entry(void *param)
{
rt_uint32_t _evt_set = 0x00;
while(1)
{
if (rt_event_recv(&t1_evt, 0x03,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &_evt_set) == RT_EOK)
{
LOG_D("%s : thread 1:[recv=0x%02x], recv.\n", __func__, _evt_set);
}
}
}
static void thread2_entry(void *param)
{
rt_uint32_t _evt_set = 0x00;
while(1)
{
if (rt_event_recv(&t2_evt, 03,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &_evt_set) == RT_EOK)
{
LOG_D("%s : thread 2:[recv=0x%02x], recv.\n", __func__, _evt_set);
}
}
}
static void thread3_entry(void *param)
{
rt_uint32_t _evt_set = 0x00;
while(1)
{
if (rt_event_recv(&t3_evt, 0x0F,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &_evt_set) == RT_EOK)
{
LOG_D("%s : thread 3:[recv=0x%02x], recv.\n", __func__, _evt_set);
}
}
}
/* 测试线程初始化 */
static void task_init(void)
{
tid1 = rt_thread_create("task1",
thread1_entry,
RT_NULL,
THREAD1_STACK_SIZE,
THREAD1_PRIORITY,
THREAD1_TIMESLICE);
tid2 = rt_thread_create("task2",
thread2_entry,
RT_NULL,
THREAD2_STACK_SIZE,
THREAD2_PRIORITY,
THREAD2_TIMESLICE);
tid3 = rt_thread_create("task3",
thread3_entry,
RT_NULL,
THREAD3_STACK_SIZE,
THREAD3_PRIORITY,
THREAD3_TIMESLICE);
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
if (tid2 != RT_NULL)
rt_thread_startup(tid2);
if (tid3 != RT_NULL)
rt_thread_startup(tid3);
}
/* 事件集测试初始化入口 */
int event_test_init(void)
{
event_init();
task_init();
return 1;
}
/* 事件集测试MSH命令 */
void event_send_task1(void)
{
rt_event_send(&t1_evt, FLAG_RECV_01);
}
void event_send_task2(void)
{
rt_event_send(&t2_evt, FLAG_RECV_02);
}
void event_send_task3(void)
{
rt_event_send(&t3_evt, FLAG_RECV_03);
}
void event_send_test(int argc, char **argv)
{
rt_uint8_t task_num = 0;
rt_uint32_t event_flag = 0;
if (argc >= 3)
{
task_num = atoi(argv[1]);
event_flag = atoi(argv[2]);
if (task_num == 0x01)
{
rt_event_send(&t1_evt, event_flag);
}
else if (task_num == 0x02)
{
rt_event_send(&t2_evt, event_flag);
}
else if (task_num == 0x03)
{
rt_event_send(&t3_evt, event_flag);
}
else
{
rt_kprintf("err! event_send_test 1 4 ");
}
}
}
MSH_CMD_EXPORT(event_send_task1, event_send_task1);
MSH_CMD_EXPORT(event_send_task2, event_send_task2);
MSH_CMD_EXPORT(event_send_task3, event_send_task3);
MSH_CMD_EXPORT(event_test_init, event init);
MSH_CMD_EXPORT(event_send_test, event_send_test);
编译与运行
msh >event_test_init
msh >list_event
event set suspend thread
-------- ---------- --------------
event3 0x00000000 001:task3
event2 0x00000000 001:task2
event1 0x00000000 001:task1
msh >event_send_test 1 4 /* 不符合的事件集,不接收 */
msh >event_send_test 1 2
msh >[D/event.test] thread1_entry : thread 1:[recv=0x02], recv.
msh >event_send_test 1 1
msh >[D/event.test] thread1_entry : thread 1:[recv=0x01], recv.
msh >event_send_test 1 3
msh >[D/event.test] thread1_entry : thread 1:[recv=0x03], recv.
msh >event_send_test 2 3
ms[D/event.test] thread2_entry : thread 2:[recv=0x03], recv.
msh >event_send_test 2 4 /* 不符合的事件集,不接收 */
msh >event_send_test 2 5 /* 事件组,只有某个事件符合 */
msh >[D/event.test] thread2_entry : thread 2:[recv=0x01], recv.
msh >event_send_test 3 5
msh >[D/event.test] thread3_entry : thread 3:[recv=0x05], recv.
msh >event_send_test 3 6
msh >[D/event.test] thread3_entry : thread 3:[recv=0x06], recv.
总结
- 灵活使用事件集,可以解决线程间事件的传输需求
- 如果需要线程间通信,需要使用消息队列等
- 熟悉内核IPC通信,正确使用事件集