4.4 V1.5核心线程管理器(KernelThreadManager)的实现
在Hello China V1.5中,对核心线程管理对象进行了优化,优化后的定义如下(V1.0版本的定义,请参考本章V1.0版本核心线程的实现):
typedef DWORD (*__KERNEL_THREAD_ROUTINE)(LPVOID); BEGIN_DEFINE_OBJECT(__KERNEL_THREAD_MANAGER) __KERNEL_THREAD_OBJECT* lpCurrentKernelThread; __PRIORITY_QUEUE* lpRunningQueue; __PRIORITY_QUEUE* lpSuspendedQueue; __PRIORITY_QUEUE* lpSleepingQueue; //__PRIORITY_QUEUE* lpReadyQueue; __PRIORITY_QUEUE* lpTerminalQueue; __PRIORITY_QUEUE* ReadyQueue[MAX_KERNEL_THREAD_PRIORITY+1]; DWORD dwNextWakeupTick; BOOL (*Initialize)(__COMMON_OBJECT* lpThis); __KERNEL_THREAD_OBJECT* (*CreateKernelThread)( __COMMON_OBJECT* lpThis, DWORD dwStackSize, DWORD dwStatus, DWORD dwPriority, __KERNEL_THREAD_ROUTINE lpStartRoutine, LPVOID lpRoutineParam, LPVOID lpReserved); __KERNEL_THREAD_OBJECT* (*GetScheduleKernelThread)( __COMMON_OBJECT* lpThis, DWORD dwPriority); VOID (*AddReadyKernelThread)( __COMMON_OBJECT* lpThis, __KERNEL_THREAD_OBJECT* lpThread); VOID (*DestroyKernelThread)(__COMMON_OBJECT* lpThis, __COMMON_OBJECT* lpKernelThread ); BOOL (*SuspendKernelThread)( __COMMON_OBJECT* lpThis, __COMMON_OBJECT* lpKernelThread ); BOOL (*ResumeKernelThread)( __COMMON_OBJECT* lpThis, __COMMON_OBJECT* lpKernelThread ); VOID (*ScheduleFromProc)( __KERNEL_THREAD_CONTEXT* lpContext ); VOID (*ScheduleFromInt)( __COMMON_OBJECT* lpThis, LPVOID lpESP ); DWORD (*SetThreadPriority)( __COMMON_OBJECT* lpKernelThread, DWORD dwNewPriority ); DWORD (*GetThreadPriority)( __COMMON_OBJECT* lpKernelThread ); DWORD (*TerminalKernelThread)( __COMMON_OBJECT* lpThis, __COMMON_OBJECT* lpKernelThread ); BOOL (*Sleep)( __COMMON_OBJECT* lpThis, DWORD dwMilliSecond ); BOOL (*CancelSleep)( __COMMON_OBJECT* lpThis, __COMMON_OBJECT* lpKernelThread ); DWORD (*GetLastError)( __COMMON_OBJECT* lpThis ); DWORD (*SetLastError)( __COMMON_OBJECT* lpThis, DWORD dwNewError ); DWORD (*GetThreadID)( __COMMON_OBJECT* lpThis ); BOOL (*SendMessage)( __COMMON_OBJECT* lpKernelThread, __KERNEL_THREAD_MESSAGE* lpMsg ); BOOL (*GetMessage)( __COMMON_OBJECT* lpKernelThread, __KERNEL_THREAD_MESSAGE* lpMsg ); BOOL (*MsgQueueFull)( __COMMON_OBJECT* lpKernelThread ); BOOL (*MsgQueueEmpty)( __COMMON_OBJECT* lpKernelThread ); BOOL (*LockKernelThread)( __COMMON_OBJECT* lpThis, __COMMON_OBJECT* lpKernelThread); VOID (*UnlockKernelThread)( __COMMON_OBJECT* lpThis, __COMMON_OBJECT* lpKernelThread); END_DEFINE_OBJECT() //End of the kernel thread manager's definition.
最大的修改,增加了一个优先队列数组,该数组以核心线程的优先级作为索引,每个元素都是一个优先队列对象,特定优先级的核心线程,全部存放在对应的优先队列内。详细的实现介绍如下。
4.4.1 V1.5核心线程队列的实现
在Hello China V1.0的实现中,所有处于就绪状态的队列,都被放在了一个队列lpReadyQueue中。而在Hello China V1.5的实现中,则定义了一个长度是最大线程优先级的队列数组,每个处于就绪状态的核心线程,都按照其优先级放到对应的队列中。在Hello China V1.5的实现中,定义了MAX_KERNEL_THREAD_PRIORITY个线程优先级,这样就绪队列数组就由MAX_KERNEL_THREAD_PRIORITY个元素组成,每个线程按照其优先级作为索引,找到队列数组对应的元素,然后插入队列。图4-16示意了这个优先队列数组的组织结构。
图4-16 1.5的核心线程队列
其他线程队列,比如挂起队列、睡眠队列等,都按照原来的组织实现。
按照这样一种组织结构实现,可很容易地实现按照优先级的线程调度策略。V1.5实现了下列严格按照优先级进行调度的调度算法:
(1)任何情况下,总是选择优先级最高的线程投入运行;
(2)对于相同优先级的线程,按照先到先服务的原则,即队头的线程对象首先得到运行(这样就要求线程队列是一个优先队列)。
为了实现上的独立性,单独把调度算法拿出来,当做一个独立的函数实现,这样需要调度的时候,只需要调用该调度函数,获得下一个要投入运行的线程即可。在将来改变调度算法的时候,只需要替换该函数即可。
下列是V1.5实现的调度算法接口函数,该函数接受一个线程优先级数值和一个指向核心线程管理对象的指针,返回一个优先级大于或等于所接受优先级的核心线程对象。若没有这样的对象(优先级大于或等于给出的优先级),则返回NULL。
__KERNEL_THREAD_OBJECT* GetScheduleKernelThread( __KERNEL_THREAD_MANAGER* lpThis, DWORD dwPriority) { if((NULL==lpThis) || (dwPriority > MAX_KERNEL_THREAD_PRIORITY)) { return NULL; } __KERNEL_THREAD_OBJECT* lpKernelThread=NULL; for(DWORD i=0;i <=MAX_KERNEL_THREAD_PRIORITY;i++) { lpKernelThread=(__KERNEL_THREAD_OBJECT*)lpMgr-> ReadyQueue[MAX_KERNEL_THREAD_PRIORITY - i]->GetHeaderElement( (__COMMON_OBJECT*)ReadyQueue[i-1], NULL); //Get the header element. if(lpKernelThread) //Get one. { return lpKernelThread; } } return lpKernelThread; //Can not find. }
上述函数完成了从就绪队列中选择一个核心线程的功能,AddReadyKernelThread则实现相反的功能——往就绪队列中添加一个核心线程对象。该函数也十分简单,如下:
static void AddReadyKernelThread(__COMMON_OBJECT* lpThis, __KERNEL_THREAD_OBJECT* lpKernelThread) { if((NULL==lpThis) || (NULL==lpKernelThread)) //Invalid parameters. { return; } //Validate this kernel thread's priority. if(lpKernelThread->dwThreadPriority MAX_KERNEL_THREAD_PRIORITY) { __BUG(); //Print out this position. return; } __PRIORITY_QUEUE* lpReadyQueue= ((__KERNEL_THREAD_MANAGER*)lpThis)->ReadyQueue[ lpKernelThread->dwThreadPriority]; lpReadyQueue->InsertIntoQueue( (__COMMON_OBJECT*)lpReadyQueue, (__COMMON_OBJECT*)lpKernelThread, 0); //Insert into queue. }
上述函数首先检查核心线程对象优先级的合法性,这是非常有必要的,因为当前的实现,是把线程的优先级作为索引,来直接索引就绪队列数组的。因此,万一出现核心线程对象的优先级超出预定范围,会导致数组越界访问。当然,优先级超出预定范围的核心线程对象,也必然是一个非法的核心线程对象。
另外,在核心线程管理对象的初始化函数(Initialize)中,需要对就绪队列数组进行初始化,即创建每一个就绪队列数组对象。