RT-Thread OS 事件集

事件集介绍来源于RT-Thread 官方文档中心,下面蓝色字体是链接

事件集的使用场合

事件集可使用于多种场合,它能够在一定程度上替代信号量,用于线程间同步。一个线程或中断服务例程发送一个事件给事件集对象,而后等待的线程被唤醒并对相应的事件进行处理。但是它与信号量不同的是,事件的发送操作在事件未清除前,是不可累计的,而信号量的释放动作是累计的。事件的另一个特性是,接收线程可等待多种事件,即多个事件对应一个线程或多个线程。同时按照线程等待的参数,可选择是 “逻辑或” 触发还是 “逻辑与” 触发。这个特性也是信号量等所不具备的,信号量只能识别单一的释放动作,而不能同时等待多种类型的释放。如下图所示为多事件接收示意图:

一个事件集中包含 32 个事件,特定线程只等待、接收它关注的事件。可以是一个线程等待多个事件的到来(线程 1、2 均等待多个事件,事件间可以使用 “与” 或者 “或” 逻辑触发线程),也可以是多个线程等待一个事件的到来(事件 25)。当有它们关注的事件发生时,线程将被唤醒并进行后续的处理动作。

 事件集也是线程间同步的机制之一,一个事件集可以包含多个事件,利用事件集可以完成一对多,多对多的线程间同步。

即一个线程与多个事件的关系可设置为:其中任意一个事件唤醒线程,或几个事件都到达后才唤醒线程进行后续的处理;同样,事件也可以是多个线程同步多个事件。这种多个事件的集合可以用一个 32 位无符号整型变量来表示,变量的每一位代表一个事件,线程通过 “逻辑与” 或“逻辑或”将一个或多个事件关联起来,形成事件组合。事件的 “逻辑或” 也称为是独立型同步,指的是线程与任何事件之一发生同步;事件 “逻辑与” 也称为是关联型同步,指的是线程与若干事件都发生同步。

RT-Thread 定义的事件集有以下特点:

1)事件只与线程相关,事件间相互独立:每个线程可拥有 32 个事件标志,采用一个 32 bit 无符号整型数进行记录,每一个 bit 代表一个事件;

2)事件仅用于同步,不提供数据传输功能;

3)事件无排队性,即多次向线程发送同一事件 (如果线程还未来得及读走),其效果等同于只发送一次。

事件集相关函数接口介绍

下面一段代码创建三个线程,th1,th2,th3,3个EVENT_FLAG,

线程1 :接收到事件1EVENT_FLAG1,执行线程1,并发送事件2

线程2 :接收到事件2EVENT_FLAG2,执行线程2,并发送事件3

线程3 :接收到事件3EVENT_FLAG3,执行线程3,并发送事件1

三个事件循环发生,所以依次执行线程1,2,3

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>


rt_thread_t th1 = NULL,th2 = NULL,th3 = NULL;
rt_event_t event;


// 事件集创建flag,建议采用 RT_IPC_FLAG_PRIO,即确保线程的实时性。
//#define RT_IPC_FLAG_FIFO                0x00            /**< FIFOed IPC. @ref IPC. */
//#define RT_IPC_FLAG_PRIO                0x01            /**< PRIOed IPC. @ref IPC. */

//事件集接收timeout
//#define RT_WAITING_FOREVER              -1              /**< Block forever until get resource. */
//#define RT_WAITING_NO                   0               /**< Non-block. */
//该标志已经作废,无论用户选择 RT_IPC_FLAG_PRIO 还是 RT_IPC_FLAG_FIFO,内核均按照 RT_IPC_FLAG_PRIO 处理
//事件集接收option ,选择 逻辑与 或 逻辑或 的方式接收事件
       RT_EVENT_FLAG_OR
       RT_EVENT_FLAG_AND

        选择清除重置事件标志位
        RT_EVENT_FLAG_CLEAR

//事件定义
#define EVENT_FLAG1 (1 << 0)
#define EVENT_FLAG2 (1 << 1)
#define EVENT_FLAG3 (1 << 2)
/**
 * rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);

// set 表示事件类型标志,option表示逻辑与 或 逻辑或 的方式接收事件
   timeout表示接收的等待时间,永久等待还是不等待
   recved表示接收的事件类型
   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); //recved用于接收发生的事件
*/
void th1_entry(void *parameter)
{
    rt_uint32_t value = 0,re_value;

    value = (rt_uint32_t)parameter; //这里parameter是4字节,所以不能用rt_uint8_t转换
    while(1)
    {
       rt_event_recv(event,EVENT_FLAG1,RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
                RT_WAITING_FOREVER,   &re_value );
       rt_kprintf("receive event 0x%x...\n",re_value);
       rt_kprintf("thread %d is runing...\n",value);
       rt_kprintf("\n");
       rt_event_send(event,EVENT_FLAG2);
       rt_thread_mdelay(1000); //
    }
}
void th2_entry(void *parameter)
{
    rt_uint32_t value = 0,re_value;
    value = (rt_uint32_t)parameter; //这里parameter是4字节,所以不能用rt_uint8_t转换
    while(1)
    {
       rt_event_recv(event,EVENT_FLAG2,RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
                RT_WAITING_FOREVER,   &re_value );
       rt_kprintf("receive event 0x%x...\n",re_value);
       rt_kprintf("thread %d is runing...\n",value);
       rt_kprintf("\n");
       rt_event_send(event,EVENT_FLAG3);
       rt_thread_mdelay(1000); //
    }
}
void th3_entry(void *parameter)
{
    rt_uint32_t value = 0,re_value;
    value = (rt_uint32_t)parameter; //这里parameter是4字节,所以不能用rt_uint8_t转换
    while(1)
    {
       rt_event_recv(event,EVENT_FLAG3,RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
                RT_WAITING_FOREVER,   &re_value );
       rt_kprintf("receive event 0x%x...\n",re_value);
       rt_kprintf("thread %d is runing...\n",value);
       rt_kprintf("\n");
       rt_event_send(event,EVENT_FLAG1);
       rt_thread_mdelay(1000); //
    }
}

int main(void)
{
//创建事件
    event = rt_event_create("event",RT_IPC_FLAG_PRIO);


//创建两个线程用来访问临界区域
    th1 = rt_thread_create("th1", th1_entry, (void*)1, 512, 10, 5);
    if(th1 == RT_NULL){
        LOG_E("th1 rt_thread_create failed...\n");
        return RT_ENOMEM;
    }
    LOG_D("th1 rt_thread_create successed...\n");
    rt_thread_startup(th1);

    th2 = rt_thread_create("th2", th2_entry, (void*)2, 512, 9, 5);
        if(th2 == RT_NULL){
            LOG_E("th2 rt_thread_create failed...\n");
            return RT_ENOMEM;
        }
    LOG_D("th2 rt_thread_create successed...\n");
    rt_thread_startup(th2);

    th3 = rt_thread_create("th3", th3_entry, (void*)3, 512, 8, 5);
           if(th3 == RT_NULL){
               LOG_E("th3 rt_thread_create failed...\n");
               return RT_ENOMEM;
           }
       LOG_D("th3 rt_thread_create successed...\n");
       rt_thread_startup(th3);
       rt_event_send(event,EVENT_FLAG1);
    return RT_EOK;
}

运行结果:

[2022-10-26_18:13:36:955]receive event 0x1...
[2022-10-26_18:13:36:955]thread 1 is runing...

[2022-10-26_18:13:36:955]receive event 0x2...
[2022-10-26_18:13:36:970]thread 2 is runing...

[2022-10-26_18:13:36:970]receive event 0x4...
[2022-10-26_18:13:36:970]thread 3 is runing...

[2022-10-26_18:13:36:970]msh >receive event 0x1...
[2022-10-26_18:13:37:974]thread 1 is runing...

[2022-10-26_18:13:37:974]receive event 0x2...
[2022-10-26_18:13:37:974]thread 2 is runing...

[2022-10-26_18:13:37:974]receive event 0x4...
[2022-10-26_18:13:37:974]thread 3 is runing...
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值