RT-Thread 内核实验 1 任务的基本管理

RT-Thread 内核实验 1任务的基本管理
实验目的:
?理解 RTOS 中任务管理的基本原理,了解任务的基本状态及其变迁过程;
?掌握 RT-Thread 任务管理子系统中的任务创建,启动,延时机制
?掌握 RT-Thread 任务管理子系统中静态任务与动态任务创建的区别

实验设计:
为了体现任务的状态切换过程,本实验设计了两个线程,分别是 thread1,thread2,此外,系统
中还有另外一个空闲任务,当没有其他任务运行时,系统自动调度空闲任务并投入运行。



实验流程:
1)系统进入应用程序入口
2)初始化静态线程thread1 ,线程的入口是thread1_entry, 参数是RT_NULL,线程栈是
thread1_stack,优先级是 30,时间片是 10 个 OS Tick
3)启动线程 thread1
4)创建动态线程 thread2,线程的入口是 thread2_entry,,参数是 RT_NULL,栈空间是 512,优
先级是 31,时间片是 25 个 OS Tick
5)启动线程 thread2
6)[1]系统首先调度 thread1 投入运行,打印第 0 次运行的信息,然后通过延时函数将自己挂起
100 个 OS Tick,系统转入调度 thread2 投入运行
7)[2]Thread2 打印第 0 次运行信息,然后通过延时函数将自己挂起 50 个 OS Tick
8)[3]系统中无任务运行,转入调度空闲任务
9)[4]50 个 OS Tick 时间后,Thread2 被唤醒,打印第 1 次运行的信息,继续通过延时函数将自
己挂起 50 个 OS Tick
10) [5]系统中无任务运行,系统转入调度空闲任务,运行 50 个 OS Tick 11) [6]Thread1 被唤醒,打印第 1 次运行信息,继续挂起 100 个 OS Tick
12) [7]Thread2 被唤醒,打印第 2 次运行的信息,继续挂起 50 个 OS Tick
13) [8]系统中无任务运行,系统转入调度空闲任务,运行 50 个 OS Tick
14) [9]Thread2 被唤醒,打印第 3 次运行的信息,继续挂起 50 个 OS Tick
15) [10]系统中无任务运行,系统转入调度空闲任务,运行 50 个 OS Tick
16) 循环上述过程

源程序说明:

/*线程 1 的对象和运行时用到的栈*/
static struct rt_thread thread1;
ALIGN(4)
static rt_uint8_t thread1_stack[512];

/*线程 1 入口*/
void thread1_entry(void* parameter)
{
int i;

while (1)
{
for (i = 0; i < 10; i ++)
{
rt_kprintf("%d\n", i);

/*延时 100 个 OS Tick */
rt_thread_delay(100);
}
}
}

/*线程 2 入口*/
void thread2_entry(void* parameter)
{
int count = 0;
while (1)
{
rt_kprintf("Thread2 count:%d\n", ++count);

/*延时 50 个 OS Tick */
rt_thread_delay(50);
}
}

/*用户应用程序入口*/
int rt_application_init()
{
rt_thread_t thread2_ptr;
rt_err_t result;
/*初始化线程 1 */
/*线程的入口是 thread1_entry ,参数是 RT_NULL
*线程栈是 thread1_stack
*优先级是 200 ,时间片是 10 个 OS Tick
*/
result = rt_thread_init(&thread1,
"thread1",
thread1_entry, RT_NULL,
&thread1_stack[0], sizeof(thread1_stack),
30, 10);

/*启动线程*/
if (result == RT_EOK) rt_thread_startup(&thread1);

/*创建线程 2 */
/*线程的入口是 thread2_entry,参数是 RT_NULL
*栈空间是 512 ,优先级是 250 ,时间片是 25 个 OS Tick
*/
thread2_ptr = rt_thread_create("thread2",
thread2_entry, RT_NULL,
512, 31, 25);

/*启动线程*/
if (thread2_ptr != RT_NULL) rt_thread_startup(thread2_ptr);

return 0;
}

输出信息:
运行程序,通过观察串口输出,就可以观察到任务的运行和切换情况了。

断点设置
使用 MDK 调试工具在程序中设置一些合理断点来运行,可以清晰地看到线程运行和切换的完
整过程。

TIPS: 动态线程和静态线程
RT-Thread 中支持静态和动态两种定义方式。用线程来举例的话,rt_thread_init 对应静态定义方
式,rt_thread_create 对应动态定义方式。
使用静态定义方式时,必须先定义静态的线程控制块,并且定义好堆栈空间,然后调用
rt_thread_init来完成线程的初始化工作。采用这种方式,线程控制块和堆栈占用的内存会放在
RW段,这段空间在编译时就已经确定,它不是可以动态分配的,所以不能被释放,而只能使
用 rt_thread_detach 函数将该线程控制块从对象管理器中脱离。
使用动态定义方式 rt_thread_create 时,RT-Thread 会动态申请线程控制块和堆栈空间。在编译时,
编译器是不会感知到这段空间的,只有在程序运行时,RT-Thread 才会从系统堆中申请分配这段
内存空间,当不需要使用该线程时,调用 rt_thread_delete 函数就会将这段申请的内存空间重新
释放到内存堆中。
这两种方式各有利弊,静态定义方式会占用 RW/ZI 空间,但是不需要动态分配内存,运行时效
率较高,实时性较好。动态方式不会占用额外的 RW/ZI空间,占用空间小,但是运行时需要
动态分配内存,效率没有静态方式高。
总的来说,这两种方式就是空间和时间效率的平衡,可以根据实际环境需求选择采用具体的分
配方式。

    推荐阅读