外观
两个特殊的任务
除用户自己创建的任务外,RT-Thread会自动创建两个特殊任务:main和 空闲任务
- main任务:系统主任务,用于执行main函数
- 空闲任务:当系统中没有其他就绪任务时运行
main任务
在RT-Thread 中,用户应用程序的main()函数并不是系统启动入口,而是作为一个线程(任务)被启动。
该任务是在系统调度器启动后由内核自动创建并运行的第一个任务。该任务由rt_application_init()创建(支持静态和动态两种方式)。
*/
void rt_application_init(void)
{
rt_thread_t tid;
#ifdef RT_USING_HEAP
tid = rt_thread_create("main", main_thread_entry, RT_NULL,
RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);
RT_ASSERT(tid != RT_NULL);
#else
rt_err_t result;
tid = &main_thread;
result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20);
RT_ASSERT(result == RT_EOK);
/* if not define RT_USING_HEAP, using to eliminate the warning */
(void)result;
#endif /* RT_USING_HEAP */
rt_thread_startup(tid);
}
该任务主要用于系统初始化后的主流程(初始化驱动、创建其他线程、启动主程序逻辑等)。在完成必要的工作之后,可以从main()返回,也可继续完成其它工作。比如增加一个while(1)循环,实现某个模块的功能。
配置参数
main任务的相关配置参数(如优先级、栈大小)放在rt_config.h中,用户可根据自己的需要进行修改。
#define RT_MAIN_THREAD_STACK_SIZE 2048 // 主线程栈大小
#define RT_MAIN_THREAD_PRIORITY 10 // 主线程优先级
空闲任务
空闲任务主要用于实现以下功能:
- 系统空闲处理:节省CPU,或进入低功耗
- 资源回收:清理已被删除的动态线程(动态任务的资源由空闲任务统一释放)
- 钩子支持:可以注册钩子函数做低优先级处理工作
相关实现代码如下。
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 /* RT_USING_SMP */
while (1)
{
#ifdef RT_USING_IDLE_HOOK
rt_size_t i;
void (*idle_hook)(void);
for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
{
idle_hook = idle_hook_list[i];
if (idle_hook != RT_NULL)
{
idle_hook();
}
}
#endif /* RT_USING_IDLE_HOOK */
#ifndef RT_USING_SMP
rt_defunct_execute();
#endif /* RT_USING_SMP */
#ifdef RT_USING_PM
void rt_system_power_manager(void);
rt_system_power_manager();
#endif /* RT_USING_PM */
}
}
void rt_thread_idle_init(void)
{
rt_ubase_t i;
char tidle_name[RT_NAME_MAX];
for (i = 0; i < _CPUS_NR; i++)
{
rt_sprintf(tidle_name, "tidle%d", i);
rt_thread_init(&idle[i],
tidle_name,
rt_thread_idle_entry,
RT_NULL,
&rt_thread_stack[i][0],
sizeof(rt_thread_stack[i]),
RT_THREAD_PRIORITY_MAX - 1,
32);
#ifdef RT_USING_SMP
rt_thread_control(&idle[i], RT_THREAD_CTRL_BIND_CPU, (void*)i);
#endif /* RT_USING_SMP */
/* startup */
rt_thread_startup(&idle[i]);
}
#ifdef RT_USING_SMP
RT_ASSERT(RT_THREAD_PRIORITY_MAX > 2);
rt_sem_init(&system_sem, "defunct", 1, RT_IPC_FLAG_FIFO);
/* create defunct thread */
rt_thread_init(&rt_system_thread,
"tsystem",
rt_thread_system_entry,
RT_NULL,
rt_system_stack,
sizeof(rt_system_stack),
RT_THREAD_PRIORITY_MAX - 2,
32);
/* startup */
rt_thread_startup(&rt_system_thread);
#endif
}
缺省情况下,空闲任务是自动创建的最低优先级任务,从而实现在没有其他任务就绪运行时执行。此外,默认的栈大小由IDLE_THREAD_STACK_SIZE配置,用户可根据自己的实现需要进行修改。
注册空闲钩子
我们可以将自定义的处理函数注册为空闲任务钩子,从而让空闲任务能够在自己的循环中调用。通过该功能,可以实现LED心跳、CPU 空闲统计等功能。
void my_idle_hook(void)
{
led_toggle(LED0); // 模拟低功耗处理或LED指示
}
RT_WEAK void rt_hw_idle_hook(void) // 若硬件中已有定义,可重写
{
my_idle_hook();
}
int hook_init(void)
{
rt_thread_idle_sethook(my_idle_hook);
return 0;
}
INIT_APP_EXPORT(hook_init);
具体要实现什么的功能,请根据实际项目的需要来决定。简单来说,就是在里面完成一些很不重要、优先级非常低的功能。
空闲任务禁止运行
根据RT-Thread的内部设计方式,除非CPU进入低功耗模式,否则必须运行一个任务。此外,空闲任务还承担着回收任务资源的操作。
因此,在空闲任务中,不能执行任何可能让该任务暂停运行的操作(CPU进入低功耗模式除外),例如:延迟(rt_thread_mdelay())、挂起(rt_thread_suspend())以及事件等待的操作。
也就是说,当其它高优先级任务都暂停运行时,空闲任务必须“一直忙个不停”,绝对“禁止停下来”。