1. 等待队列是什么

等待队列是一个轻量级的线程间异步通讯方式。

他有两个特点:

  1. 轻量: API 较少

  2. 异步:

2. 等待队列怎么使用

用户只需要使用其中的五个 API 就可以了。

  1. 初始化等待队列

    rt_inline void rt_wqueue_init(rt_wqueue_t *queue)

    queue : 消息队列控制块

  2. 加入等待队列

int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int msec)

queue : 等待队列的控制块

condition :这个形参没有使用到, 必须传递 0

msec : 需要等待的时间,单位是毫秒

  1. 唤醒等待队列

    void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key)

    queue : 等待队列的控制块

    key : 唤醒条件,目前源码中未使用

  2. 在等待队列中插入一个节点

    void rt_wqueue_add(rt_wqueue_t *queue, struct rt_wqueue_node *node)

    queue : 等待队列控制块

    node : 插入队列的节点

  3. 从等待队列移除一个节点

    void rt_wqueue_remove(struct rt_wqueue_node *node)

    node : 需要移除的节点

3. 等待队列的实现

  1. 初始化等待队列

    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)); // 初始化链表
    }
    
  2. 加入等待队列

    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;
    }
    
  3. 唤醒等待队列

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();// 开启调度
}
  1. 默认唤醒函数
int __wqueue_default_wake(struct rt_wqueue_node *wait, void *key)
{return 0;
}

这里未作任何的操作就进行了返回 0 ,这里做的太简单粗暴了。

  1. 等待队列插入一个节点
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); // 开中断
}
  1. 等待队列移除一个节点
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. 总结

  1. 等待队列的使用了关键字 rt_inline 。在 rt_device 注册设备时候都使用了 rt_wqueue_init ,这里有一个 C 语言 的小技巧,可以自己去搜索 inline 来学习一下。
  2. 进入等待队列的形参 condition 必须传递 0, 超时时间的单位是 ms
  3. 唤醒等待队列的条件 key,并未实现。如果有需要使用到等待队列的场景不要擅自修改源码,因为 RTT 设备框架 大量使用了,擅自修改会导致报错,自己可以参考官方的实现重造一个函数,去实现对 key 的操作
  4. 等待队列的源码位于/rt_thread_master/components/drivers/src/waitqueue.c
  5. 用户可以自行创建一个 API 来实现自定义的 wake_up

RT-Thread 隐藏的宝藏之等待队列相关推荐

  1. 关于RT thread系统节拍时钟的配置

    关于RT thread系统节拍时钟的配置                  -----本文基于rt-thread-3.1.3版本编写 首先,使用RTthread OS时,要配置(或者明白)它的系统节拍 ...

  2. rt thread studio使用QBOOT和片外flash实现OTA升级

    我们这里要使用单片机外部flash作为OTA的下载分区,外部flash硬件连接关系 PB3-->SPI3_CLK PB4-->SPI3_MISO PB5-->SPI3_MOSI PE ...

  3. rt thread 使用FAL遇到fal_init() undefined reference

    rt thread FAL 0.5版,之前有没有不知道,遇到一个坑. 在main.cpp里面已经 #include <fal.h> fal_init() 编译报错,说 fal_init() ...

  4. RT Thread Free Modbus移植问题整理

    RT Thread Free Modbus移植问题整理 问题描述: 在读写寄存器中,写数据正常,只能读1个寄存器的值,多个值会异常. 在移植过程中发现串口(或RS485)数据接收长度异常. 一.环境描 ...

  5. Yeelink平台使用——远程控制 RT Thread + LwIP+ STM32

    1.前言     [2014年4月重写该博文]     经过若干时间的努力终于搞定了STM32+LwIP和yeelink平台的数据互通,在学习的过程中大部分时间花在以太网协议栈学习上,但是在RT Th ...

  6. RT Thread根据开发板制作BSP方法

    之前一直不懂怎么使用RT Thread的软件包,感谢网上的大神,看了你们的博客后大概了解一些,在此做下记录.用RT Thread软件包需要RT Thread的系统,但是RT Thread和RT Thr ...

  7. RT Thread之 Uart2 操作

    官网连接:https://docs.rt-thread.org/#/rt-thread-version/rt-thread-standard/programming-manual/device/uar ...

  8. 基于rt thread smart构建EtherCAT主站

    我把源码开源到到了gitee,https://gitee.com/rathon/rt-thread-smart-soem 有兴趣的去可以下载下来跑一下 软件工程推荐用vscode 打开.rt thre ...

  9. RT Thread利用STM32CUBEMX和RT Thread studio来创建模板工程

    (1)RT Thread利用STM32CUBEMX来创建模板工程 1.参考文档: 基于 CubeMX 移植 RT-Thread Nano:RT-Thread 文档中心 注意:串口2必须使能异步模式(启 ...

  10. rt thread系统下添加wiznet软件包后,不插网线CPU利用率100%问题

    rt thread系统下添加wiznet软件包后如果不插网线的话其他任务运行很卡,使用ps命令发现优先级低的任务很多都超时了 rt thread线程错误码 添加了一个可以查看CPU利用率的软件包CPU ...

最新文章

  1. Python之旅.第九章.并发编程..
  2. Camelyon Challenge: 癌症细胞区域检测竞赛
  3. 有比 ReadWriteLock更快的锁?
  4. 设置element表格透明样式
  5. 联络员(信息学奥赛一本通-T1393)
  6. C# action 返回值_C#知识点讲解之C#delegate、event、Action、EventHandler的使用和区别
  7. FSG压缩壳和ImportREC的使用 - 脱壳篇05
  8. IAST安全扫描原理
  9. PHP爬虫最全总结1
  10. lisp自动生成界址点表_LISP语言在宗地界址点成果表的应用
  11. 基础-02-日语单词的词性与分类
  12. 市场调研报告-全球与中国商业门窗五金市场现状及未来发展趋势
  13. Cent OS 7上安装MySQL
  14. 小程序毕业设计 基于微信会议室预约小程序毕业设计开题报告功能参考
  15. 计算机启动读取硬件配置信息,开机自检画面如何查看电脑硬件配置信息
  16. Android Studio如何建立VR视频
  17. Oracle表数据转换为XML格式数据
  18. paddlepaddle测试安装_学习之路(1)PaddlePaddle的安装
  19. 思科华为设备STP、RSTP配置命令对比
  20. 虐我千百遍之NS3安装

热门文章

  1. Web页面右下角弹出窗口示例代码
  2. ฅʕ•̫͡•ʔฅ英文套装书
  3. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十二║Vue实战:个人博客第一版
  4. 电感升压电路充放电原理
  5. C# vb .net实现像素化效果滤镜打马赛克
  6. Word里怎样一次性去掉所有的超级链接
  7. word 链接本文档的超级链
  8. 血糖仪方案_无线血糖/血糖仪
  9. 二维码识别的一些资料
  10. 计算机恢复出厂设置的话有什么,电脑恢复出厂设置会怎么样,教您电脑怎么恢复出厂设置...