工程师资料

RT-Thread隐藏的宝藏之completion

2021-01-20  本文已影响0人  RTThread小师弟

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 与信号量的对比

completionAPI 个数少,资源占用少,只能释放获取,不支持多次释放

semaphoreAPI 个数多,资源占用较多,使用灵活,可以尝试获取,可以多次释放,

5. completion 如何加入工程

标准版RT-Thread中的completion源码在"\rt-thread\components\drivers\src\completion.c"在你要使用的文件中#include completion.h直接就可以使用。

Nano 版RT-Thread直接拷贝completion.c和completion.h添加到工程就可以使用。

原文链接:https://club.rt-thread.org/ask/article/2500.html

上一篇下一篇

猜你喜欢

热点阅读