原创 RT-Thread隐藏的宝藏之completion

2021-1-20 10:58 1107 2 2 分类: 软件与OS 文集: RT-Thread
1. completion 是什么

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

2. completion 怎么使用

completion 的使用非常简单

  1. 定义一个完成量

    struct rt_completion completion;
  2. 初始化完成量

    rt_completion_init(&completion);
  3. 等待完成量

    rt_completion_wait(&completion);
  4. 释放完成量

    rt_completion_done(&completion);
3. completion 的实现

completion 的 API 非常少,可以通过简单的代码去分析

  1. 初始化完成量

    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
    • 初始化完成量的链表
  2. 等待完成量(以下代码有删减)

    rt_err_t rt_completion_wait(struct rt_completion *completion, rt_int32_t timeout) { result = RT_EOK; thread = rt_thread_self(); level = rt_hw_interrupt_disable(); if (completion->flag != RT_COMPLETED) { if (timeout == 0) { } else { /* reset thread error number */ thread->error = RT_EOK; /* suspend thread */ rt_thread_suspend(thread); /* add to suspended list */ rt_list_insert_before(&(completion->suspended_list), &(thread->tlist)); /* current context checking */ RT_DEBUG_NOT_IN_INTERRUPT; /* start timer */ if (timeout > 0) { /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout); rt_timer_start(&(thread->thread_timer)); } /* enable interrupt */ rt_hw_interrupt_enable(level); /* do schedule */ rt_schedule(); /* thread is waked up */ result = thread->error; level = rt_hw_interrupt_disable(); } } /* clean completed flag */ completion->flag = RT_UNCOMPLETED; return result; }

    主要做了以下工作:

    • 关中断: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) { level = rt_hw_interrupt_disable(); completion->flag = RT_COMPLETED; if (!rt_list_isempty(&(completion->suspended_list))) { /* there is one thread in suspended list */ struct rt_thread *thread; /* get thread entry */ thread = rt_list_entry(completion->suspended_list.next, struct rt_thread, tlist); /* resume it */ rt_thread_resume(thread); rt_hw_interrupt_enable(level); /* perform a schedule */ rt_schedule(); } }

    主要做了以下工作:

    • 关中断: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 与信号量的对比
  1. completion API 个数少,资源占用少,只能释放获取,不支持多次释放
  2. semaphore API 个数多,资源占用较多,使用灵活,可以尝试获取,可以多次释放,
5. completion 如何加入工程
  1. 标准版 RT-Thread 中的 completion 源码在 "\rt-thread\components\drivers\src\completion.c"在你要使用的文件中#include completion.h直接就可以使用。
  2. Nano 版 RT-Thread 直接拷贝completion.c 和 completion.h 添加到工程就可以使用。
原文链接:https://club.rt-thread.org/ask/article/2500.html

作者: rtthread小师弟, 来源:面包板社区

链接: https://mbb.eet-china.com/blog/uid-me-3941260.html

版权声明:本文为博主原创,未经本人允许,禁止转载!

文章评论1条评论)

登录后参与讨论

curton 2021-1-20 20:42

学习了

欢迎点击


论坛> >机器人/工业电子> >工业电子与自动化


https://mbb.eet-china.com/forum/topic/85437_1_1.html
相关推荐阅读
rtthread小师弟 2020-12-10 15:58
RT-Thread新版入门系列教程18讲
...
广告
我要评论
1
2
1
2
3
4
5
6
7
8
9
0
广告
关闭 热点推荐上一条 /8 下一条