完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
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,所以超时时间的单位是 ms if ((condition) || (tick == 0)) // condition 必须传递 0 return 0; __wait.polling_thread = rt_thread_self(); //获取当前线程给到 __wait __wait.key = 0; // key 赋值 0 __wait.wakeup = __wqueue_default_wake; // 这个函数建议用户自己实现一个,默认的这个会返回0 rt_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; //需要调度设置为 1 rt_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_list rt_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)); // 移除节点 node rt_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 |
|
相关推荐
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
1122 浏览 0 评论
IaaS+on+DPU(IoD)+下一代高性能算力底座技术白皮书
2168 浏览 0 评论
飞凌嵌入式-ELFBOARD 常用的USB接口及其不同版本介绍第1期
1085 浏览 0 评论
【Vision Board创客营连载体验】RA8D1-Vision Board上OSPI-Flash实践
1560 浏览 0 评论
I.MX6ULL-飞凌 ElfBoard ELF1板卡- 应用层更改引脚复用的方法
3771 浏览 0 评论
65442 浏览 21 评论
嵌入式热门DIY项目:智能机器人开源资料合集(原理图、代码、论文)
67850 浏览 22 评论
57914 浏览 32 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-19 22:17 , Processed in 1.279999 second(s), Total 64, Slave 48 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号