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
- 初始化完成量的链表
- 设置 flag 为
等待完成量(以下代码有删减)
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-threadcomponentsdriverssrccompletion.c"
在你要使用的文件中#include completion.h
直接就可以使用。 - Nano 版 RT-Thread 直接拷贝
completion.c
和completion.h
添加到工程就可以使用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。