RT-Thread 隐藏的宝藏之等待队列
1. 等待队列是什么
等待队列是一个轻量级的线程间异步通讯方式。
他有两个特点:
轻量:
API
较少异步:
2. 等待队列怎么使用
用户只需要使用其中的五个 API
就可以了。
初始化等待队列
rt_inline void rt_wqueue_init(rt_wqueue_t *queue)
queue : 消息队列控制块
加入等待队列
int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int msec)
queue : 等待队列的控制块
condition :这个形参没有使用到, 必须传递 0
msec : 需要等待的时间,单位是毫秒
唤醒等待队列
void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key)
queue : 等待队列的控制块
key : 唤醒条件,目前源码中未使用
在等待队列中插入一个节点
void rt_wqueue_add(rt_wqueue_t *queue, struct rt_wqueue_node *node)
queue : 等待队列控制块
node : 插入队列的节点
从等待队列移除一个节点
void rt_wqueue_remove(struct rt_wqueue_node *node)
node : 需要移除的节点
3. 等待队列的实现
初始化等待队列
rt_inline void rt_wqueue_init(rt_wqueue_t *queue) // 这里使用了关键字 inline {RT_ASSERT(queue != RT_NULL); // 断言检查queue->flag = RT_WQ_FLAG_CLEAN; // 设置标志位 rt_list_init(&(queue->waiting_list)); // 初始化链表 }
加入等待队列
int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int msec) {int tick;rt_thread_t tid = rt_thread_self();// 获取当前调用等待队列的线程rt_timer_t tmr = &(tid->thread_timer);// 获取当前线程的定时器struct rt_wqueue_node __wait;// 等待队列的节点rt_base_t level;/* current context checking */RT_DEBUG_NOT_IN_INTERRUPT;tick = rt_tick_from_millisecond(msec);// 获取传递进来的时间的转换成 tick,所以超时时间的单位是 msif ((condition) || (tick == 0)) // condition 必须传递 0return 0;__wait.polling_thread = rt_thread_self(); //获取当前线程给到 __wait__wait.key = 0; // key 赋值 0__wait.wakeup = __wqueue_default_wake; // 这个函数建议用户自己实现一个,默认的这个会返回0rt_list_init(&__wait.list); // 初始化链表level = rt_hw_interrupt_disable(); // 关中断if (queue->flag == RT_WQ_FLAG_WAKEUP) // 如果队列已经是唤醒状态了{/* already wakeup */goto __exit_wakeup;}rt_wqueue_add(queue, &__wait); // 把 __wait 插入到 queue-> waiting_list 的前面rt_thread_suspend(tid);// 挂起这个线程/* start timer */if (tick != RT_WAITING_FOREVER) // 启动线程的定时器{rt_timer_control(tmr,RT_TIMER_CTRL_SET_TIME,&tick);rt_timer_start(tmr);}rt_hw_interrupt_enable(level);// 开中断rt_schedule(); // 进行一次调度level = rt_hw_interrupt_disable(); // 关中断__exit_wakeup:queue->flag = 0; // 设置 FLAG ,这个用宏的方式可能更优雅rt_hw_interrupt_enable(level); // 开中断rt_wqueue_remove(&__wait); // 从等待队列中移除 __wait 这个节点return 0; }
唤醒等待队列
void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key)
{rt_base_t level;register int need_schedule = 0;rt_list_t *queue_list;struct rt_list_node *node;struct rt_wqueue_node *entry;queue_list = &(queue->waiting_list);level = rt_hw_interrupt_disable(); // 关中断/* set wakeup flag in the queue */queue->flag = RT_WQ_FLAG_WAKEUP; // 设置等待队列的标志位if (!(rt_list_isempty(queue_list))) // 检查链表是否为空{for (node = queue_list->next; node != queue_list; node = node->next)// 循环遍历{entry = rt_list_entry(node, struct rt_wqueue_node, list);// 获取等待队列控制块if (entry->wakeup(entry, key) == 0) // wakeup 一定会返回 0{rt_thread_resume(entry->polling_thread);// 恢复这个线程need_schedule = 1; //需要调度设置为 1rt_wqueue_remove(entry); // 从等待队列的链表中移除这个等待队列break;// 跳出循环遍历}}}rt_hw_interrupt_enable(level); // 开启中断if (need_schedule)rt_schedule();// 开启调度
}
- 默认唤醒函数
int __wqueue_default_wake(struct rt_wqueue_node *wait, void *key)
{return 0;
}
这里未作任何的操作就进行了返回 0
,这里做的太简单粗暴了。
- 等待队列插入一个节点
void rt_wqueue_add(rt_wqueue_t *queue, struct rt_wqueue_node *node)
{rt_base_t level;level = rt_hw_interrupt_disable();// 关中断rt_list_insert_before(&(queue->waiting_list), &(node->list));// 把 node->list 插入到 queue->waiting_listrt_hw_interrupt_enable(level); // 开中断
}
- 等待队列移除一个节点
void rt_wqueue_remove(struct rt_wqueue_node *node)
{rt_base_t level;level = rt_hw_interrupt_disable(); //关中断rt_list_remove(&(node->list)); // 移除节点 nodert_hw_interrupt_enable(level); // 开中断
}
4. 总结
- 等待队列的使用了关键字
rt_inline
。在rt_device
注册设备时候都使用了rt_wqueue_init
,这里有一个 C 语言 的小技巧,可以自己去搜索inline
来学习一下。 - 进入等待队列的形参
condition
必须传递0
, 超时时间的单位是ms
。 - 唤醒等待队列的条件
key
,并未实现。如果有需要使用到等待队列的场景不要擅自修改源码,因为 RTT 设备框架 大量使用了,擅自修改会导致报错,自己可以参考官方的实现重造一个函数,去实现对key
的操作 - 等待队列的源码位于
/rt_thread_master/components/drivers/src/waitqueue.c
- 用户可以自行创建一个
API
来实现自定义的wake_up
RT-Thread 隐藏的宝藏之等待队列相关推荐
- 关于RT thread系统节拍时钟的配置
关于RT thread系统节拍时钟的配置 -----本文基于rt-thread-3.1.3版本编写 首先,使用RTthread OS时,要配置(或者明白)它的系统节拍 ...
- rt thread studio使用QBOOT和片外flash实现OTA升级
我们这里要使用单片机外部flash作为OTA的下载分区,外部flash硬件连接关系 PB3-->SPI3_CLK PB4-->SPI3_MISO PB5-->SPI3_MOSI PE ...
- rt thread 使用FAL遇到fal_init() undefined reference
rt thread FAL 0.5版,之前有没有不知道,遇到一个坑. 在main.cpp里面已经 #include <fal.h> fal_init() 编译报错,说 fal_init() ...
- RT Thread Free Modbus移植问题整理
RT Thread Free Modbus移植问题整理 问题描述: 在读写寄存器中,写数据正常,只能读1个寄存器的值,多个值会异常. 在移植过程中发现串口(或RS485)数据接收长度异常. 一.环境描 ...
- Yeelink平台使用——远程控制 RT Thread + LwIP+ STM32
1.前言 [2014年4月重写该博文] 经过若干时间的努力终于搞定了STM32+LwIP和yeelink平台的数据互通,在学习的过程中大部分时间花在以太网协议栈学习上,但是在RT Th ...
- RT Thread根据开发板制作BSP方法
之前一直不懂怎么使用RT Thread的软件包,感谢网上的大神,看了你们的博客后大概了解一些,在此做下记录.用RT Thread软件包需要RT Thread的系统,但是RT Thread和RT Thr ...
- RT Thread之 Uart2 操作
官网连接:https://docs.rt-thread.org/#/rt-thread-version/rt-thread-standard/programming-manual/device/uar ...
- 基于rt thread smart构建EtherCAT主站
我把源码开源到到了gitee,https://gitee.com/rathon/rt-thread-smart-soem 有兴趣的去可以下载下来跑一下 软件工程推荐用vscode 打开.rt thre ...
- RT Thread利用STM32CUBEMX和RT Thread studio来创建模板工程
(1)RT Thread利用STM32CUBEMX来创建模板工程 1.参考文档: 基于 CubeMX 移植 RT-Thread Nano:RT-Thread 文档中心 注意:串口2必须使能异步模式(启 ...
- rt thread系统下添加wiznet软件包后,不插网线CPU利用率100%问题
rt thread系统下添加wiznet软件包后如果不插网线的话其他任务运行很卡,使用ps命令发现优先级低的任务很多都超时了 rt thread线程错误码 添加了一个可以查看CPU利用率的软件包CPU ...
最新文章
- Python之旅.第九章.并发编程..
- Camelyon Challenge: 癌症细胞区域检测竞赛
- 有比 ReadWriteLock更快的锁?
- 设置element表格透明样式
- 联络员(信息学奥赛一本通-T1393)
- C# action 返回值_C#知识点讲解之C#delegate、event、Action、EventHandler的使用和区别
- FSG压缩壳和ImportREC的使用 - 脱壳篇05
- IAST安全扫描原理
- PHP爬虫最全总结1
- lisp自动生成界址点表_LISP语言在宗地界址点成果表的应用
- 基础-02-日语单词的词性与分类
- 市场调研报告-全球与中国商业门窗五金市场现状及未来发展趋势
- Cent OS 7上安装MySQL
- 小程序毕业设计 基于微信会议室预约小程序毕业设计开题报告功能参考
- 计算机启动读取硬件配置信息,开机自检画面如何查看电脑硬件配置信息
- Android Studio如何建立VR视频
- Oracle表数据转换为XML格式数据
- paddlepaddle测试安装_学习之路(1)PaddlePaddle的安装
- 思科华为设备STP、RSTP配置命令对比
- 虐我千百遍之NS3安装
热门文章
- Web页面右下角弹出窗口示例代码
- ฅʕ•̫͡•ʔฅ英文套装书
- 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十二║Vue实战:个人博客第一版
- 电感升压电路充放电原理
- C# vb .net实现像素化效果滤镜打马赛克
- Word里怎样一次性去掉所有的超级链接
- word 链接本文档的超级链
- 血糖仪方案_无线血糖/血糖仪
- 二维码识别的一些资料
- 计算机恢复出厂设置的话有什么,电脑恢复出厂设置会怎么样,教您电脑怎么恢复出厂设置...