2.当loop线程在控制台1中执行,并且在控制台2中执行suspend命令时,为什么控制台1中的loop线程处于就绪状态而不是运行状态?
答:当在控制台2 中执行suspend命令时,实质上是优先级为24的控制台2线程抢占了处理器,也就是控制台2线程处于运行状态,所以此时loop线程处于就绪状态了。 4. 总结一下在图5-3中显示的转换过程,哪些需要使用线程控制块中的上下文(将线程控制块中的上下文恢复到处理器中,或者将处理器的状态复制到线程控制块的上下文中),哪些不需要使用,并说明原因。
答:一个进程在运行过程中或执行系统调用,或产生了一个中断事件,处理器都进行一次模式切换,操作系统接收控制权,有关系统例程完成必须的操作后,或恢复被中断进程或切换到新进程。当系统调度新进程占有处理器时,新老进程随之发生上下文切换,因此,进程的运行被认为是在进程的上下文中执行,这时的控制权在操作系统手中,它在完成必要的操作后,可以恢复被中断的进程或切换到别的进程。
实验5 进程的同步
一、 实验目的
使用EOS的信号量,编程解决生产者—消费者问题,理解进程同步的意义。 调试跟踪EOS信号量的工作过程,理解进程同步的原理。
修改EOS的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。 二、 实验内容
1 、准备实验
2 、使用EOS的信号量解决生产者-消费者问题 3 、调试EOS信号量的工作过程 4、 修改EOS的信号量算法 if (Semaphore->Count>0){ Semaphore->Count--; flag=STATUS_SUCCESS;
}//如果信号量大于零,说明尚有资源,可以为线程分配 else
flag=PspWait(&Semaphore->WaitListHead, Milliseconds); KeEnableInterrupts(IntState); // 原子操作完成,恢复中断。 return flag;
}//否则,说明资源数量不够,不能再为线程分配资源,因此要使线程等待
if (Semaphore->Count + ReleaseCount > Semaphore->MaximumCount) {Status = STATUS_SEMAPHORE_LIMIT_EXCEEDED;} Else{
//记录当前的信号量的值//
if(NULL!=PreviousCount){*PreviousCount=Semaphore->Count;} int mm=Semaphore->Count;
//目前仅实现了标准记录型信号量,每执行一次信号量的释放操作 只能使信号量的值增加1.//
while ((!ListIsEmpty(&Semaphore->WaitListHead))&&(ReleaseCount)){ PspWakeThread(&Semaphore->WaitListHead, STATUS_SUCCESS); PspThreadSchedule(); ReleaseCount--; }
Semaphore->Count=mm+ReleaseCount; //可能有线程被唤醒,执行线程调度。// Status=STATUS_SUCCESS:} 三、问题答案及参考代码
1.思考在ps/semaphore.c文件内的PsWaitForSemaphore和PsReleaseSemaphore函数中,为什么要使用原子操作?
答:在执行释放信号量和等待信号量时,是不允许CPU响应外部中断的,否则,会产生不可预料的结果。
4.根据本实验3.3.2节中设置断点和调试的方法,自己设计一个类似的调 试方案来验证消费者线程在消费24号产品时会被阻塞, 直到生产者线程生产了24 号产品后,消费者线程才被唤醒并继续执行的过程。
答:调试方案如下: ① 删除所有的断点。 ② 按F5启动调试。OS Lab会首先弹出一个调试异常对话框。 ③ 在调试异常对话框中选择“是”,调试会中断。 ④ 在Consumer函数中等待Full信号量的代码行(第173行) WaitForSingleObject(FullSemaphoreHandle, INFINITE); 添加一个断点。 ⑤ 在“断点”窗口(按Alt+F9打开)中此断点的名称上点击右键。 ⑥ 在弹出的快捷菜单中选择“条件”。 ⑦ 在“断点条件”对话框(按F1获得帮助)的表达式编辑框中,输入表达式“i == 24”。 ⑧ 点击“断点条件”对话框中的“确定”按钮。 ⑨ 按F5继续调试。只有当消费者线程尝试消费24号产品时才会在该条件断 点处中断。
实验6 时间片轮转调度
一、实验目的
调试EOS的线程调度程序,熟悉基于优先级的抢先式调度。 为EOS添加时间片轮转调度,了解其它常用的调度算法。 二、实验内容 1 、准备实验
2、 阅读控制台命令“rr”相关的源代码 3、调试线程调度程序
4 、为EOS添加时间片轮转调度 VOID
PspRoundRobin(VOID) {
if(NULL!=PspCurrentThread&&Running==PspCurrentThread->State) {
PspCurrentThread->RemainderTicks--; if(0==PspCurrentThread->RemainderTicks){
PspCurrentThread->RemainderTicks=TICKS_OF_TIME_SLICE; if(BIT_TEST(PspReadyBitmap, PspCurrentThread->Priority)) {PspReadyThread(PspCurrentThread);}}
二、 问题答案及参考代码
1. 结合线程调度执行的时机,说明在ThreadFunction函数中,为什么可以使用“关中断”和“开中断”的方法来保护控制台这种临界资源。一般情况下,应该使用互斥信号量(MUTEX)来保护临界资源,但是在ThreadFunction函数中却不能使用互斥信号量,而只能使用“关中断”和“开中断”的方法,结合线程调度的对象说明这样做的原因。
答:关中断后CPU就不会响应任何由外部设备发出的硬中断(包括定时计数器中断和键盘中断等)了,也就不会发生线程调度了,从而保证各个线程可以互斥的访问控制台。这里绝对不能使用互斥信号量(mutex)保护临界资源的原因:如果使用互斥信号量,则那些由于访问临界区而被阻塞的线程,就会被放入互斥信号量的等待队列,就不会在相应优先级的就绪列中了,而时间轮转调度算法是对就绪队列的线程进行轮转调度,而不是对这些被阻塞的线程进行调度,也就无法进行实验了。使用“关中断”和“开中断”进行同步就不会改变线程的状态,可以保证那些没有获得处理器的线程都在处于就绪队列中。
3.使用低优先级线程也能获得执行机会的调度算法:在ke/sysproc.c文件中的ConsoleCmdRoundRobin函数调用Sleep函数语句的后面添加下面的语言,即可以演优先级线程抢占处理器后,低优先级线程无法运行的情况,待高优先级线程结束后,低优先级线程才能够继续运行。
HANDLE ThreadHandle;
THREAD_PARAMETER ThreadParameter; _asm(“cli”);
ThreadParameter.Y=20;
ThreadParameter.StdHandle=StdHandle; ThreadParameter=(HANDLE)CreateThread{
0,ThreadFunction,(PVOID)&ThreadParameter,0,NULL); PsSetThreadPriority(ThreeadHandle,9); _asm(“sti”); Sleep(10*1000);
TerminateThread(ThreadHandle,0); CloseHandle(ThreadHandle); Sleep(10*1000);
解决该问题的最简单的方法是实现动态优先级算法。动态优先级是指在创建进程时所赋予的优先级,可以随线程的推进而改变,以便获得良好的调度性能。例如,可用规定,在就绪队列中的线程,随着其等待时间的增长,其优先级以速率X增加,并且正在执行的线程,其优先级以速率y下降。这样,在各个线程具有不同优先级的情况下,对于优先级低的线程,在等待足够的时间后,其优先级便可能升为最高,从而获得被执行的机会。此时,在基于优先级的抢占式调度算法、时间片轮转调度算法和动态优先级算法的共同作用下,可防止一个高优先级的长作业长期的垄断处理器。
4.EOS内核时间片大小取60ms(和Windows操作系统完全相同),在线程比较多时,就可以观察出线程轮流执行的情况(因为此时一次轮转需要60ms,20个线程轮流执行一次需要60×20=1200ms,也就是需要1秒多的时间,所以EOS的控制台上可以清楚地观察到线程轮流执行的情况)。但是在Windows、Linux等操作系统启动后,正常情况下都有上百个线程在并发执行,为什么觉察不到它们被轮流执行, 并且每个程序都运行的很顺利呢?
答:在Windows、linux等操作系统中,虽然都提供了时间片轮转调度算法却很少真正被派上用场,下面解释原因,在Windows任务管理器中,即使系统中已经运行了数百个线程,
相关推荐: