RT-Thread 入门学习笔记 - 熟悉rt_event事件集的使用

发布于 2021-03-23 22:40:43

前言

  • 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 :代码实现了一个复位事件集的命令处理,不常用。

测试例程

  • 测试环境可以在PC模拟器或STM32开发板上验证
#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通信,正确使用事件集
0 条评论

发布
问题