Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
DIY综合交流区
[RealTouch例程]事件的基本使用
发布于 2012-08-19 16:34:11 浏览:6377
订阅该版
实验目的 ? 了解事件的基本用法 ? 熟练使用事件实现多个线程间同步 硬件说明 本实验使用RT-Thread官方的Realtouch开发板作为实验平台。涉及到的硬件主要为: ? 串口3,作为rt_kprintf输出 需要连接JTAG扩展板,具体请参见《Realtouch开发板使用手册》 实验原理及程序结构 实验设计 本实验演示在RT-Thread中使用事件(EVENT)实现多线程间同步和通信。 事件是一个32bit(4个字节)的变量,其中每一个位可以表示代表一种事件。接收事件的线程既可以在多个事件同时发生后(即多个bit位同时置1)触发,正如本例中线程1中第一条语句所演示的那样。 也可以多个事件任意一个发生后(即多个bit位任意一个置位)就可以触发。 主程序中创建三个线程,线程1接收事件标志。线程2和线程3则向发送事件标志。 本实验同样使用静态事件作为演示,涉及静态事件初始化/脱离。动态事件创建/删除类似,不再赘述。 源程序说明 本实验对应kernel_event_basic。 系统依赖 在rtconfig.h中需要开启 ``` #define RT_USING_EVENT``` 此项必须,开启此项即可使用事件机制。 ``` #define RT_USING_HEAP``` 此项可选,开启此项可以创建动态线程和动态邮箱,如果使用静态线程和静态信号量,则此项不是必要的。 ``` #define RT_USING_CONSOLE``` 此项必须,本实验使用rt_kpriintf向串口打印按键信息,因此需要开启此项 主程序说明 在applications/application.c中定义静态消息队列控制块、存放消息的缓冲区。如下所示 定义全局变量代码 ```/* 事件控制块 */ static struct rt_event event; ```在applications/application.c中的 int rt_application_init()函数中,初始化静态事件。 初始化静态事件代码 ``` rt_err_t result; /* 初始化事件对象 */ rt_event_init(&event, "event", RT_IPC_FLAG_FIFO); if (result != RT_EOK) { rt_kprintf("init event failed. "); return -1; } ```在int rt_application_init()初始化名为“thread1”的thread1的静态线程,如下所示。 创建线程1代码 ``` rt_thread_init(&thread1, "thread1", thread1_entry, RT_NULL, &thread1_stack[0], sizeof(thread1_stack),8,50); rt_thread_startup(&thread1); ```其线程入口函数如下所示,线程1调用rt_event_recv函数,等待event事件上bit3和bit5代表的事件发生;第三个参数中的RT_EVENT_FLAG_AND 表示事件标志采用与,即等待的多个事件同时发生此函数才返回,否则继续等待事件;RT_EVENT_FLAG_CLEAR表示接收到事件后将事件相关位清除;RT_WAITING_FOREVER表示如果等待的时间没有发生,则永远等待下去。 线程1先等待bit3和bit5表示的事件,若都发生后则向串口打印信息,否则永远等待下去。之后使用rt_thread_delay延时1秒钟。之后再次等待bit3和bit5表示的事件,这一次使用的是RT_EVENT_FLAG_OR,这表示bit3和bit4任意一个事件发生都可以。 线程1代码 ```ALIGN(RT_ALIGN_SIZE) //设置下一句线程栈数组为对齐地址 static char thread1_stack[1024]; //设置线程堆栈为1024Bytes struct rt_thread thread1; //定义静态线程数据结构 /* 线程1入口 */ /* 线程1入口函数 */ static void thread1_entry(void *param) { rt_uint32_t e; /* receive first event */ if (rt_event_recv(&event, ((1 << 3) | (1 << 5)), RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e) == RT_EOK) { rt_kprintf("thread1: AND recv event 0x%x ", e); } rt_kprintf("thread1: delay 1s to prepare second event "); rt_thread_delay(RT_TICK_PER_SECOND); /* receive second event */ if (rt_event_recv(&event, ((1 << 3) | (1 << 5)), RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e) == RT_EOK) { rt_kprintf("thread1: OR recv event 0x%x ", e); } rt_kprintf("thread1 leave. "); } ```在int rt_application_init()初始化名为”thread2”的thread2的静态线程,如下所示。 初始化线程2代码 ``` rt_thread_init(&thread2, "thread2", thread2_entry, RT_NULL, &thread2_stack[0], sizeof(thread2_stack),9,50); rt_thread_startup(&thread2); ```其线程入口函数如下所示,线程2调用rt_event_send发送bit3事件,之后调用rt_kprintf打印结束信息后,线程函数运行结束。 线程2代码 ```ALIGN(RT_ALIGN_SIZE) //设置下一句线程栈数组为对齐地址 static char thread2_stack[1024]; //设置线程堆栈为1024Bytes struct rt_thread thread2; //定义静态线程数据结构 /* 线程2入口 */ static void thread2_entry(void *param) { rt_kprintf("thread2: send event1 "); rt_event_send(&event, (1 << 3)); rt_kprintf("thread2 leave. "); } ```在int rt_application_init()初始化名为”thread3”的thread3的静态线程,如下所示。 初始化线程3代码 ``` rt_thread_init(&thread3, "thread3", thread3_entry, RT_NULL, &thread3_stack[0], sizeof(thread3_stack),10,50); rt_thread_startup(&thread3); ```其线程入口函数如下所示,线程2首先调用rt_event_send发送bit5事件,延时20个tick之后,再次发送bit5表示的事件,线程函数运行结束。 ```ALIGN(RT_ALIGN_SIZE) //设置下一句线程栈数组为对齐地址 static char thread3_stack[1024]; //设置线程堆栈为1024Bytes struct rt_thread thread3; //定义静态线程数据结构 /* 线程3入口函数 */ static void thread3_entry(void *param) { rt_kprintf("thread3: send event2 "); rt_event_send(&event, (1 << 5)); rt_thread_delay(20); rt_kprintf("thread3: send event2 "); rt_event_send(&event, (1 << 5)); rt_kprintf("thread3 leave. "); } ```编译调试及观察输出信息 编译请参见《RT-Thread配置开发环境指南》完成编译烧录,参考《Realtouch开发板使用手册》完成硬件连接,连接扩展板上的串口和jlink。 运行后可以看到如下信息: 串口信息 | / - RT - Thread Operating System / | 1.1.0 build Aug 9 2012 2006 - 2012 Copyright by rt-thread team thread2: send event1 thread2 leave. thread3: send event2 thread1: AND recv event 0x28 thread1: delay 1s to prepare second event thread3: send event2 thread3 leave. thread1: OR recv event 0x20 thread1 leave. 结果分析 整个程序运行过程中各个线程的状态变化: rt_application_init中创建了三个线程,thread1(线程1)、thread2(线程2)、thread3(线程3),线程1的优先级最高,线程2的优先级次之,线程3优先级最低。 线程1首先运行,其线程处理函数中调用rt_event_recv,以‘AND’方式接收event上bit3和bit5表示的事件,如果这两个事件中只要有任何一个没有发生,则线程1就会被挂起到event事件上, 即只有当bit3和bit5表示的事件都发生后,线程1才被唤醒。显然,线程1被挂起后,调度器会重新调度,线程2被调度运行,它会打印 thread2: send event1 然后向事件event发送bit3代表的事件。之后线程2退出。此时依然不满足线程1的等待的事件条件,bit3置位,bit5依然为0,因此线程1依然被挂起在事件event上。调度器继续调度,线程3被调度运行,线程3打印 thread3: send event2 然后使用rt_event_send(&event, (1 << 5))向事件event发送bit5代表的事件,此时线程1等待的条件满足,线程1的状态由挂起转换成就绪。线程1的优先级高于线程3,因此在下一个系统tick中断后,线程1被调度运行。线程1接收事件event后,会将event的bit3和bit5清0,接下来向串口打印: thread1: AND recv event 0x28 thread1: delay 1s to prepare second event 之后,线程1再次接收事件bit3和bit5,这次是以‘OR’的方式等待事件,即bit3和bit5中任意一个发生则线程1等待的条件满足,否则被挂起在事件上。 此时线程1再次被挂起,等待bit3或bit5代表的事件发生。内核再次调度线程3运行,线程3中调用rt_event_send(&event, (1 << 5)),这会将线程1从挂起态转换成就绪态,但并不会立刻执行状态切换,线程切换会发生在下一次系统tick中断中。 因此线程3继续运行,打印 thread3 leave. 在之后的系统tick中断中,线程1被调度运行,打印 thread1: OR recv event 0x20 thread1 leave. 线程1的处理函数也运行完毕后退出,之后内核调度运行IDLE线程。 以上就是整个实验中,各个线程的状态转换过程。 总结 本实验演示了RT-Thread中事件作为多线程通信的用法,以静态事件控制块为例,动态事件的用法类似,只是创建/删除需要使用 rt_event_create/rt_event_delete函数,读者可以使用动态事件重复本实验。 [attach]0[/attach] 下载附件 [实验2_9事件的基本使用.pdf](https://oss-club.rt-thread.org/uploads/88_d999ed33c135f47d3ee275ffd8f77ecf.pdf) 下载附件 [1_kernel_event_basic.zip](https://oss-club.rt-thread.org/uploads/3089_6242e193eb2db73814acce78b7daea00.zip)
查看更多
4
个回答
默认排序
按发布时间排序
bloom5
2012-09-05
这家伙很懒,什么也没写!
添加例程 [attach]1279[/attach]
weiyuliang
2012-12-12
这家伙很懒,什么也没写!
嗯,很感谢,把事件讲述的很详尽, 但是作为一个初学者,有时候在不同的情况下不知道采用什么那,信号量、互斥量、消息、邮箱、事件、希望后面有一个完成的分析,在不同的情况下采用不同的东西实现线程同步,以及线程之间数据的操作...
a105
2013-10-04
这家伙很懒,什么也没写!
事件初始化时的返回值没有赋给result而导致初始化出错
撰写答案
登录
注册新账号
关注者
0
被浏览
6.4k
关于作者
shaolin
这家伙很懒,什么也没写!
提问
115
回答
444
被采纳
0
关注TA
发私信
相关问题
1
[项目]搞个开源的硬件项目
2
硬件计划贴,及时更新,欢迎提意见
3
软件计划贴,及时更新,欢迎提意见::WMA,MOUNT,LWIP等问题急需解决.
4
MMS协议
5
定点的wma解压库-libwma
6
QQ群记录 [20090821]
7
STM32网络收音机PCB报名征集
8
第一版调试记录
9
第二版硬件讨论
10
RADIO项目相关模块规格--欢迎大家自己做板时规格与此兼容,减少重复劳动
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
ulog
C++_cpp
at_device
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
8
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
3
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部