第二步:编写Os86tiny的线程管理功能

FAQ

和上一步的例子相比,这一步的例子增加了5个线程管理函数,它们是Thread_Create、Thread_Destroy、Thread_Resume、Thread_Suspend、Thread_GetCurrentThreadId。本例只支持最多4个线程的管理。

 

Thread_Create 支持创建一个线程

Thread_Destroy 支持删除一个线程

Thread_Resume 支持恢复运行一个被挂起(暂停)的线程

Thread_Suspend 支持挂起(暂停)一个线程

Thread_GetCurrentThreadId 支持获取当前线程的线程标示符

 

和上一步的例子相比,本例用一个堆栈池(其实是一个堆栈数组)ThreadStacks代替了上例中的子任务堆栈SubTaskStack,并增加了一个线程描述子数组ThreadDescriptors和一个就绪队列ReadyQueue。本例重新编写了任务调度函数__TaskSchedule,以队列的方式来调度线程。从本例开始,任务调度函数__TaskSchedule被称为线程调度函数。

 

在本例中,删除或挂起当前线程是一个难点。本例使用了一种滞后删除/挂起的方法来解决这个问题,并在线程调度函数__TaskSchedule中为此作了特殊处理,请仔细阅读。另外,线程的上下文(Context)不仅包括寄存器上下文,而且还增加了一些线程初始化所需的变量,详情请查看结构St_ThreadContext和函数SubTaskInit的定义。

 

为保证线程管理操作不可被中断,线程管理函数在工作时会关闭系统中断,在完成工作后再打开系统中断。为支持这个功能,本例在hal.asm中实现了关中断函数__SystemLock和打开中断函数__SystemUnlock。

 

为了启动本例的线程管理功能,使用者必须调用Thread_Init函数。这个函数要求使用者指定一个根线程,即系统中的第一个线程。一旦这个函数被调用,系统将初始化线程管理库,并把控制权交给根线程。(注意,根线程是不能结束的,否则系统会崩溃)

 

本例把上一步例子中的主任务MainTask指定成根线程,并在MainTask创建其它的线程。为避免根线程结束,本例在MainTask中增加了一个空闲循环。这样,一旦所有线程的工作完成,系统将进入这个空闲循环,并变为空闲状态。

 

下载这一步例子的源代码

 

下一步:支持简单的文本显示(仅在PC上)

 


FAQ:

 

1.问:实现线程切换的基本原理是什么?
答:实现线程切换的基本原理是:通过保存当前线程的处理器状态(主要是指所有寄存器的值 - 包括PC或IP寄存器)并恢复下一个线程的处理器状态,从而使处理器在不同线程之间实现处理器状态的完全转移。通过使用这种保存/恢复的方法,确保了一个线程在运行时不会破坏其它线程的处理器状态,从而使多个线程能够共享一个处理器。

 

2.问:通常用unsigned定义一个变量的时候需要明确定义变量的类型,格式为:unsigned type variable 为什么有些地方可以直接这样定义:unsigned variable? 答:在C语言中,用unsigned定义一个变量的时候有一个默认的数据类型为int,如果没有明确指定数据类型那么数据类型为默认值,即unsigned variable = unsigned int variable

 

【编写者:易昭华】