【RT-Thread基础教程】Delay函数与空闲线程及其钩子函数
@TOC
前言
在 RT-Thread 操作系统中,Delay 函数和空闲线程钩子函数是实现任务调度和系统优化的重要工具。Delay 函数用于在任务中创建延迟,而空闲线程及其钩子函数则可以用于执行系统空闲时间内的一些操作,如任务监控、能耗优化等。本文将介绍 Delay 函数的作用和用法,以及空闲线程及其钩子函数的概念,并简要讨论它们在 RT-Thread 中的应用。
一、Delay函数
1.1 rt_thread_delay()函数
我们可以使用下面这个函数延时tick
rt_err_t rt_thread_delay(rt_tick_t tick);
参数为你要延时的tick。当前线程会阻塞让出 CPU 资源
1.2 rt_thread_mdelay()函数
我们可以使用下面这个函数实现ms级延时:
rt_err_t rt_thread_mdelay(rt_int32_t ms);
参数1为你要延时的ms时间
当前线程会阻塞让出 CPU 资源
1.3 rt_hw_us_delay()函数
我们可以使用下面这个函数实现微秒的延时
void rt_hw_us_delay(rt_uint32_t us);
参数为你要延时的us时间。当前线程不会阻塞,这个函数是"死等指定时间“
1.4 rt_thread_delay_until函数
我们可以使用下面这个函数延时指定延时到tick+n
rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick);
参数1为开始的tick,参数2为延时的tick多少
1.5 获取当前tick数
我们可以使用下面这个函数获取当前系统的tick数:
rt_tick_t rt_tick_get(void);
他返回当前的tick
二、空闲线程与钩子函数
2.1 空闲线程
空闲线程是在操作系统中用于处理系统空闲时间的特殊线程。当系统中没有其他任务需要执行时,CPU 就会执行空闲线程。这个线程的任务通常是执行一些系统维护工作,或者在低功耗模式下帮助节省能源。
换句话说,就像是一个不忙的保安一样,当没有其他事情需要他处理时,他就会在岗位上待着,保持警惕,随时准备处理突发事件。
空闲线程优先级最低:它不能阻碍用户线程运行
空闲线程要么处于就绪态,要么处于运行态,永远不会挂起
空闲线程的优先级为最低,这意味着一旦某个用户的线程变为就绪态,那么空闲线程马上被切换出去,让这个用户线程运行。
在这种情况下,我们说用户线程"抢占"(pre-empt)了空闲线程,这是由调度器实现的。要注意的是:如果某
个线程被删除,那么需要确保后面空闲线程有机会执行,否则就无法释放被删除线程的内存。
下面的这个函数就是空闲线程的函数了,如果定义了RT_USING_IDLE_HOOK
宏,他会去把idle_hook_list
里面的东西取出来,然后执行。rt_thread_idle_excute
函数用于清楚工作
static void rt_thread_idle_entry(void *parameter)
{
#ifdef RT_USING_SMP
if (rt_hw_cpu_id() != 0)
{
while (1)
{
rt_hw_secondary_cpu_idle_exec();
}
}
#endif
while (1)
{
#ifdef RT_USING_IDLE_HOOK
rt_size_t i;
for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
{
if (idle_hook_list[i] != RT_NULL)
{
idle_hook_list[i]();
}
}
#endif
rt_thread_idle_excute();
#ifdef RT_USING_PM
rt_system_power_manager();
#endif
}
}
rt_thread_idle_excute
函数实现如下:
void rt_thread_idle_excute(void)
{
/* Loop until there is no dead thread. So one call to rt_thread_idle_excute
* will do all the cleanups. */
/* disable interrupt */
RT_DEBUG_NOT_IN_INTERRUPT;
#ifdef RT_USING_HEAP
while (1)
{
rt_base_t lock;
rt_thread_t thread;
lock = rt_hw_interrupt_disable();
/* check whether list is empty */
if (!_has_defunct_thread())
{
rt_hw_interrupt_enable(lock);
break;
}
/* get defunct thread */
thread = rt_list_entry(rt_thread_defunct.next,
struct rt_thread,
tlist);
/* remove defunct thread */
rt_list_remove(&(thread->tlist));
/* release thread's stack */
RT_KERNEL_FREE(thread->stack_addr);
/* delete thread object */
rt_object_delete((rt_object_t)thread);
rt_hw_interrupt_enable(lock);
}
#endif
}
首先他会取出要释放内存的线程:
/* get defunct thread */
thread = rt_list_entry(rt_thread_defunct.next,
struct rt_thread,
tlist);
接下来他会把这个线程从线程链表里面移除:
/* remove defunct thread */
rt_list_remove(&(thread->tlist));
然后他会释放对应的栈空间:
/* release thread's stack */
RT_KERNEL_FREE(thread->stack_addr);
最后他会删除这个线程:
/* delete thread object */
rt_object_delete((rt_object_t)thread);
2.2 钩子函数
我们可以添加一个空闲线程的钩子函数,空闲线程的循环每执行一次,就会调用一次钩子函数。钩子函数的作用有这些:
执行一些低优先级的、后台的、需要连续执行的函数
测量系统的空闲时间:空闲线程能被执行就意味着所有的高优先级线程都停止了,所以测量空闲线程占据的时间,就可以算出处理器占用率。
让系统进入省电模式:空闲线程能被执行就意味着没有重要的事情要做,当然可以进入省电模式了。
空闲线程的钩子函数的限制:
不能导致空闲线程进入挂起状态、关闭状态
不能使使用 rt_thread_delay()等可能会导致线程挂起的函数
malloc()、free()等内存相关的函数,内部使用了信号量作为临界区保护,也不允许在钩子函数中使用
如果你往idle_hook_list
里面添加了你需要的执行的钩子函数,下面这段代码会取出来执行他们
#ifdef RT_USING_IDLE_HOOK
rt_size_t i;
for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
{
if (idle_hook_list[i] != RT_NULL)
{
idle_hook_list[i]();
}
}
idle_hook_list
的定义:static void (*idle_hook_list[RT_IDLE_HOOK_LIST_SIZE])(void);
你需要写一个无返回值无参数的函数给idle_hook_list
总结
Delay 函数和空闲线程钩子函数是 RT-Thread 中重要的功能模块,有助于实现任务调度和系统优化。Delay 函数允许任务在一定时间内延迟执行,从而实现任务之间的时间控制和同步。空闲线程及其钩子函数则提供了在系统空闲时间内执行额外操作的机会,如任务监控、能耗优化等。合理利用 Delay 函数和空闲线程钩子函数可以提高系统的性能和稳定性,是 RT-Thread 应用开发中不可或缺的重要工具
- 点赞
- 收藏
- 关注作者
评论(0)