**空闲线程(idle)**是系统创建的最低优先级的线程,线程状态永远为就绪态。当系统中无其他就绪线程存在时,调度器将调度到空闲线程,它通常是一个死循环,且永远不能被挂起。另外,空闲线程在 RT-Thread 也有着它的特殊用途:
若某线程运行完毕,系统将自动删除线程:自动执行 rt_thread_exit() 函数,先将该线程从系统就绪队列中删除,再将该线程的状态更改为关闭状态,不再参与系统调度,然后挂入 rt_thread_defunct 僵尸队列(资源未回收、处于关闭状态的线程队列)中,最后空闲线程会回收被删除线程的资源。
空闲线程也提供了接口来运行用户设置的钩子函数,在空闲线程运行时会调用该钩子函数,适合钩入功耗管理、看门狗喂狗等工作。空闲线程必须有得到执行的机会,即其他线程不允许一直while(1)死卡,必须调用具有阻塞性质的函数;否则例如线程删除、回收等操作将无法得到正确执行。
之前一直没懂用户线程在工程中应该执行的次数,通过实验代码验证,只要线程完成了所设定的任务,然后就按上文高亮部分的内容进行处理。不想看代码的,可直接看最后的图片。
#include <rtthread.h>
rt_uint32_t g_tmp;
ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread_test1;
void test1_thread_entry(void* parameter)
{
rt_uint32_t i;
g_tmp =0;
rt_kprintf("g_tmp=:%d \r\n", g_tmp);
for(i=0; i<20; i++)//100
{
g_tmp++;
rt_kprintf("g_tmp2=:%d \r\n", g_tmp);
}
rt_kprintf("g_tmp4=:%d \r\n", g_tmp);
}
ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread_test2;
void test2_thread_entry(void* parameter)
{
rt_thread_delay(1);// 1
g_tmp++;
rt_kprintf("g_tmp3=:%d \r\n", g_tmp);
}
int demo_thread_creat(void)
{
/* 创建静态线程:优先级 16,时间片 2 个系统滴答 */
rt_err_t result1;
rt_err_t result2;
result1 = rt_thread_init(&thread_test1,
"test1",
test1_thread_entry,
RT_NULL,(rt_uint8_t*)&thread1_stack[0],
sizeof(thread1_stack),
16,
2);
if(result1 == RT_EOK)
{
rt_thread_startup(&thread_test1);
}
/* 创建静态线程:优先级 15,时间片 1 个系统滴答 */
result2 = rt_thread_init(&thread_test2,
"test2",
test2_thread_entry,
RT_NULL,
(rt_uint8_t*)&thread2_stack[0],
sizeof(thread2_stack),
15,
1);
if(result2 == RT_EOK)
{
rt_thread_startup(&thread_test2);
}
}
INIT_APP_EXPORT(demo_thread_creat);
可以看到,本文的线程入口函数 只设置了运行一次,线程运行完毕后(任务完成),系统将自动删除线程(查询不到用户线程)。如果线程入口函数是包含无限循环体(自然也带延时函数),执行list_thread 时肯定会有相应的用户线程存在。