sunsili 发表于 2022-2-8 18:26:06

RT-Thread隐藏的宝藏之completion

本帖最后由 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
[*]初始化完成量的链表
[*]等待完成量(以下代码有删减)
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;
[*]返回线程状态
这样就完成了线程的挂起。


[*]完成完成量(以下代码有删减)
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 与信号量的对比
[*]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 添加到工程就可以使用。

页: [1]
查看完整版本: RT-Thread隐藏的宝藏之completion