1. completion 是什么
completion
直接翻译过来是完成,所以我们可以称 rt_completion
为 完成量。在 RT-Thread 的文档中心 中讲线程间同步时,介绍了 信号量, 互斥量, 事件集 。 rt_completion
是一个 轻量级的二值信号量。
2. completion 怎么使用
completion 的使用非常简单
定义一个完成量
1struct rt_completion completion;
初始化完成量
1rt_completion_init(&completion);
等待完成量
1rt_completion_wait(&completion);
- 释放完成量
<br />rt_completion_done(&completion);<br />
3. completion 的实现
completion 的 API 非常少,可以通过简单的代码去分析
初始化完成量
1void rt_completion_init(struct rt_completion *completion) 2{ 3 rt_base_t level; 4 RT_ASSERT(completion != RT_NULL); 5 6 level = rt_hw_interrupt_disable(); 7 completion->flag = RT_UNCOMPLETED; 8 rt_list_init(&completion->suspended_list); 9 rt_hw_interrupt_enable(level);10}
干了两件事:
- 设置 flag 为
RT_UNCOMPLETED
- 初始化完成量的链表
2.等待完成量(以下代码有删减)
1rt_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 7 level = rt_hw_interrupt_disable(); 8 if (completion->flag != RT_COMPLETED) 9 {10 if (timeout == 0)11 {1213 }14 else15 {16 /* reset thread error number */17 thread->error = RT_EOK;1819 /* suspend thread */20 rt_thread_suspend(thread);21 /* add to suspended list */22 rt_list_insert_before(&(completion->suspended_list),23 &(thread->tlist));2425 /* current context checking */26 RT_DEBUG_NOT_IN_INTERRUPT;2728 /* start timer */29 if (timeout > 0)30 {31 /* reset the timeout of thread timer and start it */32 rt_timer_control(&(thread->thread_timer),33 RT_TIMER_CTRL_SET_TIME,34 &timeout);35 rt_timer_start(&(thread->thread_timer));36 }37 /* enable interrupt */38 rt_hw_interrupt_enable(level);3940 /* do schedule */41 rt_schedule();4243 /* thread is waked up */44 result = thread->error;4546 level = rt_hw_interrupt_disable();47 }48 }49 /* clean completed flag */50 completion->flag = RT_UNCOMPLETED;5152 return result;53}
主要做了以下工作:
- 关中断: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;
- 返回线程状态
这样就完成了线程的挂起。
3.完成完成量(以下代码有删减)
1 void rt_completion_done(struct rt_completion *completion) 2 { 3 level = rt_hw_interrupt_disable(); 4 completion->flag = RT_COMPLETED; 5 6 if (!rt_list_isempty(&(completion->suspended_list))) 7 { 8 /* there is one thread in suspended list */ 9 struct rt_thread *thread;1011 /* get thread entry */12 thread = rt_list_entry(completion->suspended_list.next,13 struct rt_thread,14 tlist);1516 /* resume it */17 rt_thread_resume(thread);18 rt_hw_interrupt_enable(level);1920 /* perform a schedule */21 rt_schedule();22 }23 }
主要做了以下工作:
- 关中断: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
添加到工程就可以使用
推荐阅读
【20210305期AI简报】基于TensorRT完成NanoDet模型部署
【20210219期AI简报】嵌入式机器学习(TinyML)实战教程、谷歌开源计算框架JAX...
【20210205期AI简报】联发科发布二代5G基带芯片发布
文章转载于微信公众号:RTThread物联网操作系统
作者:王海靖