谷动谷力

 找回密码
 立即注册
查看: 851|回复: 0
打印 上一主题 下一主题
收起左侧

RT-Thread隐藏的宝藏之completion

[复制链接]
跳转到指定楼层
楼主
发表于 2022-2-8 18:26:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 sunsili 于 2022-2-8 20:25 编辑

RT-Thread隐藏的宝藏之completion                                                        


1. completion 是什么
completion 直接翻译过来是完成,所以我更愿意称 rt_completion 为 完成量。在 RT-Thread 的文档中心 中讲线程间通讯(IPC)时,只介绍了,信号量, 互斥量, 事件集,其实  rt_completion 可以认为是轻量级的二值信号量。

2.  completion 怎么使用
completion 的使用非常简单
  • 定义一个完成量
    struct rt_completion completion;
  • 初始化完成量
    rt_completion_init(&completion);
  • 等待完成量
    rt_completion_wait(&completion);
  • 释放完成量
    rt_completion_done(&completion);

3.  completion 的实现
completion 的 API 非常少,可以通过简单的代码去分析
  • 初始化完成量
    void rt_completion_init(struct rt_completion *completion){    rt_base_t level;    RT_ASSERT(completion != RT_NULL);    level = rt_hw_interrupt_disable();    completion->flag = RT_UNCOMPLETED;    rt_list_init(&completion->suspended_list);    rt_hw_interrupt_enable(level);}
    干了两件事:
    • 设置 flag 为 RT_UNCOMPLETED
    • 初始化完成量的链表
  • 等待完成量(以下代码有删减)
    1. rt_err_t rt_completion_wait(struct rt_completion *completion,
    2.                             rt_int32_t            timeout)
    3. {
    4.     result = RT_EOK;
    5.     thread = rt_thread_self();

    6.     level = rt_hw_interrupt_disable();
    7.     if (completion->flag != RT_COMPLETED)
    8.     {
    9.         if (timeout == 0)
    10.         {
    11.         
    12.         }
    13.         else
    14.         {
    15.             /* reset thread error number */
    16.             thread->error = RT_EOK;

    17.             /* suspend thread */
    18.             rt_thread_suspend(thread);
    19.             /* add to suspended list */
    20.             rt_list_insert_before(&(completion->suspended_list),
    21.                                   &(thread->tlist));

    22.             /* current context checking */
    23.             RT_DEBUG_NOT_IN_INTERRUPT;

    24.             /* start timer */
    25.             if (timeout > 0)
    26.             {
    27.                 /* reset the timeout of thread timer and start it */
    28.                 rt_timer_control(&(thread->thread_timer),
    29.                                  RT_TIMER_CTRL_SET_TIME,
    30.                                  &timeout);
    31.                 rt_timer_start(&(thread->thread_timer));
    32.             }
    33.             /* enable interrupt */
    34.             rt_hw_interrupt_enable(level);

    35.             /* do schedule */
    36.             rt_schedule();

    37.             /* thread is waked up */
    38.             result = thread->error;

    39.             level = rt_hw_interrupt_disable();
    40.         }
    41.     }
    42.     /* clean completed flag */
    43.     completion->flag = RT_UNCOMPLETED;

    44.     return result;
    45. }
    复制代码

    主要做了以下工作:
    • 关中断:rt_hw_interrupt_disable();
    • 挂起当前线程:rt_thread_suspend(thread);
    • 把挂起状态插入到线程的链表中:rt_list_insert_before
    • 确保当前函数执行不是在中断中:RT_DEBUG_NOT_IN_INTERRUPT;
    • 设置并启动定时器:rt_timer_start(&(thread->thread_timer));
    • 开中断:rt_hw_interrupt_enable(level);
    • 开调度器:rt_schedule();
    • 获取当前线程状态:result = thread->error;
    • 设置完成量的标志位:completion->flag = RT_UNCOMPLETED;
    • 返回线程状态
这样就完成了线程的挂起。

  • 完成完成量(以下代码有删减)
    1. void rt_completion_done(struct rt_completion *completion)
    2. {
    3.     level = rt_hw_interrupt_disable();
    4.     completion->flag = RT_COMPLETED;

    5.     if (!rt_list_isempty(&(completion->suspended_list)))
    6.     {
    7.         /* there is one thread in suspended list */
    8.         struct rt_thread *thread;

    9.         /* get thread entry */
    10.      thread = rt_list_entry(completion->suspended_list.next,
    11.                                struct rt_thread,
    12.                             tlist);

    13.         /* resume it */
    14.         rt_thread_resume(thread);
    15.         rt_hw_interrupt_enable(level);

    16.         /* perform a schedule */
    17.         rt_schedule();
    18.     }
    19. }
    复制代码



    主要做了以下工作:
    • 关中断:rt_hw_interrupt_disable();
    • 设置 flag 为 RT_COMPLETED
    • 检查链表不为空:rt_list_isempty
    • 获取到当前等待完成量的句柄:rt_list_entry
    • 启动被挂起的线程:rt_thread_resume(thread);
    • 开中断:rt_hw_interrupt_enable(level);
    • 开调度:rt_schedule();

4. completion 与信号量的对比
  • completion API 个数少,资源占用少,只能释放获取,不支持多次释放
  • semaphore API 个数多,资源占用较多,使用灵活,可以尝试获取,可以多次释放,

5. completion 如何加入工程
  • 标准版 RT-Thread 中的 completion 源码在 "\rt-thread\components\drivers\src\completion.c"在你要使用的文件中#include completion.h直接就可以使用。
  • Nano 版 RT-Thread 直接拷贝completion.c 和 completion.h 添加到工程就可以使用。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-4-26 09:30 , Processed in 0.074977 second(s), 37 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表