版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、操作系统实验报告实验一 线程的状态和转换(5分)1 实验目的和要求目的:熟悉线程的状态及其转换,理解线程状态转换与线程调度的关系。要求:(1)跟踪调试EOS线程在各种状态间的转换过程,分析EOS中线程状态及其转换的相关源代码;(2)修改EOS的源代码,为线程增加挂起状态。2 完成的实验内容2.1 EOS线程状态转换过程的跟踪与源代码分析(分析EOS中线程状态及其转换的核心源代码,说明EOS定义的线程状态以及状态转换的实现方法;给出在本部分实验过程中完成的主要工作,包括调试、跟踪与思考等)实验主要分析EOS的下列线程状态转换:线程由阻塞状态进入就绪状态。线程由运行状态进入就绪状态。线程由就绪状态
2、进入运行状态。线程由运行状态进入阻塞状态。Loop函数:系统准备了控制台命令“loop”,命令函数是ke/sysproc.c文件中ConsoleCmdLoop函数(Line 797),此函数中使用LoopThreadFunction创建优先级为8的线程。在线程转换实验中,loop线程的主要作用是表示线程的状态,如运行、阻塞、挂起、就绪、恢复状态。loop线程代码分析如下:LoopThreadFunction(PVOID Param) ULONG i;ULONG ThreadID = GetCurrentThreadId();COORD CursorPosition;HANDLE StdHand
3、le = (HANDLE)Param;for (i = 0; i < 24; i+) fprintf(StdHandle, "n"); / 清理整个屏幕的内容。CursorPosition.X = 0; / 设置线程输出内容显示的位置CursorPosition.Y = 0;for (i=0;i+) / 死循环。SetConsoleCursorPosition(StdHandle, CursorPosition);fprintf(StdHandle, "Loop thread ID %d : %u ", ThreadID, i); / 格式:Thr
4、ead ID 线程ID : 执行计数return 0;分析:CreateThread用于创建线程,第一个“0”对应于LPSECURITY_ATTRIBUTES,即对象描述符,这个结构为很多函数创建对象是提供安全性设置,第二个“0”和“NULL”为CreateThread的配置参数。LoopThreadFunction是创建loop循环线程,在这个函数中用于在控制台显示的代码在787行的循环函数.2.1.1线程由阻塞状态进入就绪状态通过实验步骤的调试,可以将线程由阻塞状态进入就绪状态的步骤总结如下:将线程从等待队列中移除 将线程的状态由 Waiting 修改为 Zero将线程插入其优先级对应的就
5、绪队列的队尾将线程的状态由 Zero 修改为 Ready状态转换过程中使用到的函数为PspUnwaitThread函数和PspWakeThread 函数,其中PspUnwaitThread函数是使处于等待状态的线程脱离等待队列并转入Zero状态,即使线程脱离阻塞状态。PspWakeThread函数是改变线程的转台值,使Zero状态或者运行状态的线程转入就绪状态。从函数代码分析转换的功能PspUnwaitThread函数VOID PspUnwaitThread( IN PTHREAD Thread )/功能描述:使处于等待状态的线程脱离等待队列并转入 Zero 状态。/参数: Thread -
6、目标线程对象指针。ASSERT(Waiting = Thread->State); / 将线程从所在等待队列中移除并修改状态码为Zero。ListRemoveEntry (&Thread->StateListEntry);Thread->State = Zero; / 如果线程注册了等待计时器,则注销等待计时器。if (STATUS_TIMEOUT = Thread->WaitStatus) KeUnregisterTimer(&Thread->WaitTimer);分析:函数的参数Thread是目标线程对象指针,执行如下。ASSERT(Waiti
7、ng = Thread->State);首先测试线程是不是在等待队列,如果不是则结束函数的执行,在程序运行时,主要用于调试,使其不容易出现错误或异常。ListRemoveEntry(&Thread->StateListEntry);Thread->State = Zero;将线程从所在等待队列中移除并修改状态码为Zero。其中&Thread->StateListEntry是线程队列,ListRemoveEntry函数是移除等待队列的堆栈,第二句是使线程状态修改为Zero。PspWakeThread函数PspWakeThread(IN PLIST_ENTR
8、Y WaitListHead,IN STATUS WaitStatus) /功能描述:唤醒指定等待队列的队首线程。/参数: WaitListHead - 等待队列指针。 /WaitStatus - 被唤醒线程从PspWait返回的返回值。 PTHREAD Thread;If (! ListIsEmpty (WaitListHead) / 唤醒等待队列的队首线程。Thread = CONTAINING_RECORD (WaitListHead->Next, THREAD, StateListEntry);PspUnwaitThread (Thread);PspReadyThread (Th
9、read);Thread->WaitStatus = WaitStatus; / 设置线程从PspWait返回的返回值。 else Thread = NULL ;return Thread;分析: 函数中使处于等待队列中的线程的状态发生改变的函数是“PspReadyThread (Thread)”,功能是使 Zero 状态或者运行状态的线程转入就绪状态。与PspUnwaitThread函数联合使用,从而完成线程从阻塞到就绪的状态改变。2.1.2线程由运行状态进入就绪状态 通过试验调试,可以将线程由运行状态进入就绪状态的步骤总结如下:(1) 线程中断运行,将线程中断运行时的上下文保存到线程
10、控制块中。(2) 如果处于运行状态的线程被更高优先级的线程抢先,就需要将该线程插入其优先级对应的就绪队列的队首。(3) 将线程的状态由 Running 修改为 Ready。状态转换在PspSelectNextThread函数中完成,主要分为两部分,被中断的线程处于运行状态和非运行状态,代码分析如下:运行状态:if (NULL != PspCurrentThread && Running = PspCurrentThread->State)if (0 != PspReadyBitmap && HighestPriority > PspCurrentTh
11、read->Priority) / 如果存在比当前运行线程优先级更高的就绪线程,当前线程应被抢先。/ 因为当前线程仍处于运行状态,所以被高优先级线程抢先后应插入其/ 优先级对应的就绪队列的队首。ListInsertHead (&PspReadyListHeads PspCurrentThread->Priority,&PspCurrentThread->StateListEntry);BIT_SET (PspReadyBitmap, PspCurrentThread->Priority);PspCurrentThread->State = Read
12、y; else / 当前线程继续运行。MmSwapProcessAddressSpace (PspCurrentThread->Attached as);return &PspCurrentThread->KernelContext;分析:第一句判断当前非空进程的状态是否是运行,是的话执行下面过程;后一个if语句比较运行进程的优先级,如果有等高的优先级的进程进行申请,该正在运行的进程被中断,状态改为就绪(ready),转换过程在else上一句执行。非运行状态:if (0 = PspReadyBitmap) / 被中断运行线程处于非运行状态,必须存在一个可运行的就绪线程。AS
13、SERT (FALSE);KeBugCheck ("No ready thread to run!");分析:当前被中断的进程处于非运行状态时,要么使其运行,要么等待可运行的就绪进程。2.1.3线程由运行状态进入就绪状态将线程从其优先级对应的就绪队列中移除将线程的状态由 Ready 修改为 Zero将线程的状态由 Zero 修改为 Running将线程的上下文从线程控制块(TCB)复制到处理器的各个寄存器中,让线程从上次停止运行的位置继续运行。VOIDPspUnreadyThread( PTHREAD Thread )/功能描述:取消线程的就绪状态,使线程转入 Zero 状
14、态。/参数: Thread - 当前处于就绪状态的线程的指针。ASSERT(NULL != Thread && Ready = Thread->State);/ 将线程从所在的就绪队列中取出,如果线程优先级对应的就绪队列变为空, / 则清除就绪位图中对应的位。/ListRemoveEntry(&Thread->StateListEntry);if(ListIsEmpty(&PspReadyListHeadsThread->Priority) BIT_CLEAR(PspReadyBitmap, Thread->Priority);Threa
15、d->State = Zero;分析:函数将线程状态转入就绪,使其状态为zero,再转回PspSelectNextThread将函数状态值设为2,即运行状态。2.1.4线程由由运行状态进入阻塞状态将线程插入等待队列的队尾。将线程的状态由 Running 修改为 Waiting将线程中断执行,并将处理器上下文保存到该线程的线程控制块中。PspWait(IN PLIST_ENTRY WaitListHead,IN ULONG Milliseconds) WaitStatus。ASSERT(0 = KeGetIntNesting();ASSERT(Running = PspCurrentThr
16、ead->State);ASSERT(0 != PspReadyBitmap);if(0 = Milliseconds) return STATUS_TIMEOUT;/ 将当前线程插入等待队列的队尾并修改线程状态码为Waiting。ListInsertTail(WaitListHead, &PspCurrentThread->StateListEntry);PspCurrentThread->State = Waiting;/ 如果不是永久等待,就注册一个用于超时唤醒线程的等待计时器。if (INFINITE != Milliseconds) KeInitialize
17、Timer( &PspCurrentThread->WaitTimer, Milliseconds, PspOnWaitTimeout, (ULONG_PTR)PspCurrentThread );KeRegisterTimer(&PspCurrentThread->WaitTimer);PspCurrentThread->WaitStatus = STATUS_TIMEOUT; else PspCurrentThread->WaitStatus = STATUS_SUCCESS;/ 当前线程进入等待状态后需要让出处理器(让权等待),执行线程调度。Psp
18、ThreadSchedule();/ 线程被唤醒继续执行,返回等待结果状态码。return PspCurrentThread->WaitStatus; 分析:线程由运行状态改为阻塞状态,相应的状态值应该由”2”改为”0”,在上面的代码中, “PspCurrentThread->State = Waiting”是完成这一转换功能的。2.2为线程增加挂起状态的实现(给出实现方法的简要描述、源代码、测试和结果等)(1)添加代码的原理:首先调用 ListRemoveEntry 函数将线程从挂起线程队列中移除,然后调用 PspReadyThread 函数将线程恢复为就绪状态,最后调用 Psp
19、ThreadSchedule 宏函数执行线程调度,让刚刚恢复的线程有机会执行。(2)源代码:STATUSPsResumThread ( IN HANDLE hThread )/功能描述:恢复指定的线程。/参数: hThread - 需要被恢复的线程的句柄。/返回值:如果成功则返回 STATUS_SUCCESS。STATUS Status;BOOL IntState;PTHREAD Thread;/ 根据线程句柄获得线程对象的指针/Status = ObRefObjectByHandle(hThread, PspThreadType, (PVOID*)&Thread);if (EOS_S
20、UCCESS(Status) IntState = KeEnableInterrupts(FALSE);/ 关中断if (Zero = Thread->State) / 在此添加代码将线程恢复为就绪状态 ListRemoveEntry(&Thread->StateListEntry); PspReadyThread(Thread); PspThreadSchedule();/添加完成Status = STATUS_SUCCESS; else Status = STATUS_NOT_SUPPORTED;KeEnableInterrupts(IntState);/ 开中断ObD
21、erefObject(Thread);return Status;分析:本实验添加了三行代码,实际测试时,只添加中间的函数“PspReadyThread”,resume仍然正常执行,原因是只有一个进程从就绪列表中取出,若是连续两个进程先执行suspend,则会出错,所以严谨的写法应把前后两行代码加上。ListRemoveEntry用于将进程从挂起状态移除,PspThreadSchedule()调用此进程。(3)测试: 首先调用loop循环进程,在并行的控制台中输入suspend 进程号,返回原控制台观察现象,然后执行resume 进程号,再返回控制台查看,并输出当前进程所有的进程的状态信息。(
22、4)测试结果: 进程状态信息:ready为就绪,waiting为阻塞,running为执行3 其他需要说明的问题 3.1思考一下,在本实验中,当 loop 线程处于运行状态时,EOS 中还有哪些线程,它们分别处于什么状态。可以使用控制台命令 pt 查看线程的状态。 答:如上图所示,2号进程处于就绪状态,2028处于挂起状态,31运行 3.2当 loop 线程在控制台 1 中执行,并且在控制台 2 中执行 suspend 命令时,为什么控制台 1 中的 loop线程处于就绪状态而不是运行状态?答:打开控制台3时(控制台2在本实验中不能使用),loop线程处于活动就绪状态,此时在控制台3中使用挂起
23、原语Suspend可以将该线程挂起,该线程便会转入静止就绪状态。处于静止就绪状态的线程,不会再被调度执行,直到使用原语Resume将该线程恢复为活动就绪状态。3.3总结一下在图 5-3 中显示的转换过程,哪些需要使用线程控制块中的上下文(将线程控制块中的上下文恢复到处理器中,或者将处理器的状态复制到线程控制块的上下文中),哪些不需要使用,并说明原因。答:新建->就绪 :当创建一个进程或线程时,新进程的主线程或者新线程都会被初始化为就绪状态,并被放入就绪队列中。就绪->运行 :当调度程序认为某个处于就绪状态的线程应当执行时,便使其成为当前运行的线程,该线程就会从就
24、绪状态进入运行状态。 运行->就绪 :当前运行线程因时间片用完或被更高优先级线程抢先时,当前运行线程就会由运行状态转入就绪状态。 运行->阻塞 :当前运行线程可能因调用API函数WaitForSingleObject等待事件或者执行I/O请求而被阻塞,从而由运行状态转入阻塞状态。 阻塞->就绪 :处于阻塞状态的线程所等待的事件变为有效后,或等待超时后,该线程将被唤醒,从而由阻塞状态进入就绪状态。 任意状态->结束状态 线程可以由任意一个状态转入结束状态。例如,线程执行完毕会由运行状态转入结束
25、状态,就绪线程或者阻塞线程如果被强制结束,也会转入结束状态。3.4. 在本实验 3.2 节中总结的所有转换过程都是分步骤进行的,为了确保完整性,显然这些转换过程是不应该被打断的,也就是说这些转换过程都是原语操作(参见本书第 2.6 节)。请读者找出这些转换过程的原语操作(关中断和开中断)是在哪些代码中完成的。答:在ps/psspnd.c文件中已经为原语Suspend实现了对应的函数PsSuspendThread: STATUS PsSuspendThread( IN HANDLE hThread ) STATUS
26、 Status; BOOL IntState; PTHREAD Thread; Status = ObRefObjectByHandle(hThread, PspThreadType, (PVOID*)&Thread); if (EOS_SUCCESS(Status) IntState = KeEnableInterrupts(FALSE); / 关中断 if (Ready
27、 = Thread->State) PspUnreadyThread(Thread); ListInsertTail(&SuspendListHead, &Thread>StateListEntry); Status = STATUS_SUCCESS; else Status = STATUS_NOT_SUPPORTED; KeEnableInterrupts(IntState);
28、; / 开中断 ObDerefObject(Thread); return Status; 实验二 进程的同步(7分)1 实验目的和要求目的:理解进程同步的原理和意义,掌握信号量的实现方法和应用。要求:(1)使用EOS的信号量,实现生产者-消费者问题; (2)跟踪调试EOS信号量的工作过程,分析EOS信号量实现的源代码;(3)修改EOS信号量的实现代码,使之支持等待超时唤醒和批量释放功能。2 完成的实验内容2.1 使用EOS的信号量实现生产者-消费者问题(简要说明使用EOS的信号量解决生产者-消费者问题的实现方法;给出在
29、本部分实验过程中完成的主要工作,包括调试、跟踪、测试与思考等)生产者和消费者函数执行流程如下图所示实现方法: 主函数创建Mutex对象实现信号量的互斥访问,PV原语的实现过程在Producer函数和Consumer函数中给出.同时main函数创建Empty和Full信号量对象,并创建生产者和消费者进程,当这两个进程执行完后结束main函数.可以看出,main函数对给出了解决生产者和消费者问题所需要的基本信号量和相应的函数. Producer函数:函数执行时首先检查是否生产完毕,如果是则结束该函数,否则等待Empty信号量,再检查Empty是否是空的,是则生产.等待Mutex信号量,实现对于临界
30、资源的互斥访问,满足条件时生产一个产品,占用一个缓冲区,并循环向右移动缓冲区指针。然后释放Mutex对象,释放临界资源。释放修改后的Full信号量对象,在此延时500ms在进行循环生产。 Consumer函数:与Producer函数一样,首先检查是否消费完毕,如果是则结束函数,否则等待Full信号量,如果Full信号量非空,那么Consumer可以消费产品。接着等待Mutex信号量,进入临界区,实现对于临界资源的互斥访问。临界区内首先执行消费一个产品,清空一个缓冲区,循环向后移动缓冲区指针,释放Mutex对象,结束临界区访问,最后释放Empty信号量对象。函数最后需要判断是否是前10个产品,如
31、果是等待2000ms,否则等待100ms,再循环执行。 调试: 使用 pc.c 文件中的源代码,替换之前创建的 EOS 应用程序项目中 EOSApp.c 文件内的源代码。按 F7 生成修改后的 EOS 应用程序项目。按 F5 启动调试。OS Lab 会首先弹出一个调试异常对话框。在调试异常对话框中选择“否”,继续执行。立即激活虚拟机窗口查看生产者消费者同步执行的过程,待应用程序执行完毕后,结束此次调试。调试结果如下图所示思考:生产者线程和消费者线程是如何使用 Mutex、Empty 信号量和 Full 信号量来实现同步的?在两个线程函数中对这三个同步对象的操作能够改变顺序吗?答:三个信号量的初
32、始值分别为Mutex=1(实现临界资源的互斥访问)、Empty=10(缓冲区的容纳个数)、Full=0,当存在一个生产者线程访问缓冲池时,首先对Empty减1,如果大于0,则说明还有剩余缓冲区可以让生产者放入产品,否则生产者线程进入等待队列;再对Mutex减1,如果大于等于0,则说明没有线程占用缓冲池,否则生产者线程进入等待队列。生产完产品后,对Mutex加1,解除封锁;再对Full加1,说明生产了一个产品占用了一个缓冲区。消费者线程同理,对信号量的操作顺序与生产者线程相反。不能对这三个同步对象的操作改变顺序,否则可能造成死锁。生产者在生产了 13 号产品后本来要继续生产 14 号产品,可此时
33、生产者为什么必须等待消费者消费了 4 号产品后,才能生产 14 号产品呢?生产者和消费者是怎样使用同步对象来实现该同步过程的呢?答:因为临界资源的访问限制,程序中限定了缓冲池的大小为10,只有缓冲池有空余时生产者才能向里边放产品,同时只有缓冲池有产品时消费者才能向外取东西。当生产者生产了13号产品后,共生产了从0到13的14个产品,但是只消费了从0到3的4个产品,所以缓冲池中的10个缓冲区就都被占用了,所以不能继续生产14号产品,而要等到消费者消费掉一个产品后,缓冲池有空余位置,才能继续生产14号产品。当生产者线程生产了13号产品后,此时Full信号量的值为10,而Empty信号量的值为0,此
34、时若生产者线程要再生产一个产品,先对Empty减1,此时Empty值小于零,生产者线程进入等待队列;而此时若有一个消费者线程要消费一个产品,先对Full减1,此时Full值为9,大于0,如果没有线程占用缓冲池,消费者可以消费一个产品。这样,生产者和消费者就能实现同步过程了。2.2 EOS信号量工作过程的跟踪与源代码分析(分析EOS信号量实现的核心源代码,简要阐述其实现方法;给出在本部分实验过程中完成的主要工作,包括调试、跟踪与思考等)实现方法:EOS信号量实现是按照上面流程图的操作进行,线面通过分析代码具体查看执行的过程 (1)创建信号量 信号量结构体(SEMAPHORE)中的各个成员变量是由
35、 API 函数 CreateSemaphore 的对应参数初始化的, Main()函数的第77行用于创建空信号量EmptySemaphoreHandle = CreateSemaphore(BUFFER_SIZE, BUFFER_SIZE, NULL) CreatSemaphore在流程图中的三个信号量的创建过程中都有用到,在使用时有必要了解该函数的执行过程CreateSemaphore(IN LONG InitialCount, IN LONG MaximumCount IN PSTR Name) STATUS Status;HANDLE Handle;Status = PsCreateSe
36、maphoreObject(InitialCount,MaximumCount,Name,&Handle );PsSetLastError(TranslateStatusToError(Status);return EOS_SUCCESS(Status) ? Handle : NULL;分析:该函数使用时参数包括信号量的初始值、最大值和信号量名称。PsInitializeSemaphore (IN PSEMAPHORE Semaphore, IN LONG InitialCount, IN LONG MaximumCount)/功能描述:初始化信号量结构体。/参数:Semaphore
37、- 要初始化的信号量结构体指针。InitialCount - 信号量的初始值,不能小于 0 且不能大于 MaximumCount。MaximumCount - 信号量的最大值,必须大于 0。ASSERT(InitialCount >= 0 && InitialCount <= MaximumCount && MaximumCount > 0);Semaphore->Count = InitialCount;Semaphore->MaximumCount = MaximumCount;ListInitializeHead(&S
38、emaphore->WaitListHead);分析:该函数定义了信号量的结构体,在创建mutex信号量、full信号量和empty信号量的时候,需要预先执行该函数初始化信号量结构体,才能使用其他函数。 (2)等待、释放信号量生产者和消费者刚开始执行时,用来放产品的缓冲区都是空的,所以生产者在第一次调用WaitForSingleObject 函数等待 Empty 信号量时,应该不需要阻塞就可以立即返回。生产者进程代码:ULONG Producer(PVOID Param) int i;int InIndex = 0;for (i = 0; i < PRODUCT_COUNT; i+
39、) WaitForSingleObject(EmptySemaphoreHandle, INFINITE);WaitForSingleObject(MutexHandle, INFINITE);printf("Produce a %dn", i);BufferInIndex = i;InIndex = (InIndex + 1)% BUFFER_SIZE;ReleaseMutex(MutexHandle); /释放mutexReleaseSemaphore(FullSemaphoreHandle, 1, NULL);Sleep(500); / 休息一会。每 500 毫秒生产
40、一个数。return 0;分析:WaitForSingleObject()函数执行了两次,第一次执行是等待empty信号量,第二次执行是等待mutex(用于访问临界资源定义的信号量),与流程图中的步骤相对应。BufferInIndex = i;InIndex = (InIndex + 1)% BUFFER_SIZE;则是被访问的临界资源,在缓冲区添加资源,ReleaseMutex函数释放mutex信号量,ReleaseSemaphore释放full信号量。Sleep(500);是定时500ms的函数。PsWaitForSemaphore函数: PsWaitForSemaphore(IN PSE
41、MAPHORE Semaphore,IN ULONG Milliseconds )/功能描述:信号量的 Wait 操作(P 操作)。/参数:Semaphore - Wait 操作的信号量对象。Milliseconds - 等待超时上限,单位毫秒。返回值:STATUS_SUCCESS。当你修改信号量使之支持超时唤醒功能后,如果等待超时,应该返回 STATUS_TIMEOUT。BOOL IntState;ASSERT(KeGetIntNesting() = 0); / 中断环境下不能调用此函数。IntState = KeEnableInterrupts(FALSE); / 开始原子操作,禁止中断。
42、/ 目前仅实现了标准记录型信号量,不支持超时唤醒功能,所以 PspWait 函数的第二个参数的值只能是 INFINITE。Semaphore->Count-;if (Semaphore->Count < 0) PspWait(&Semaphore->WaitListHead, INFINITE);KeEnableInterrupts(IntState); / 原子操作完成,恢复中断。return STATUS_SUCCESS;分析:在Producer进程和Consumer进程函数中,WaitForSingleObject需要调用此函数,主要是用来完成信号量的等待
43、操作,即P操作。PsReleaseSemaphore函数STATUSPsReleaseSemaphoreObject(IN HANDLE Handle,IN LONG ReleaseCount,IN PLONGPreviousCount)STATUS Status;PSEMAPHORE Semaphore;if (ReleaseCount < 1) return STATUS_INVALID_PARAMETER; / 由 semaphore 句柄得到 semaphore 对象的指针。Status = ObRefObjectByHandle(Handle, PspSemaphoreType
44、, (PVOID*)&Semaphore);if (EOS_SUCCESS(Status) Status = PsReleaseSemaphore(Semaphore, ReleaseCount, PreviousCount);ObDerefObject(Semaphore);return Status;分析:生产者、消费者和main函数中都需要使用ReleaseSemaphore来释放使用过的信号量,函数有3个句柄,处理子函数,释放值,当前值。内部函数通过调用PsReleaseSemaphore函数来具体实现释放信号量。2.3支持等待超时唤醒和批量释放功能的EOS信号量实现(给出实现
45、方法的简要描述、源代码、测试和结果等)问题:在目前 EOS Kernel 项目的 ps/semaphore.c 文件中,PsWaitForSemaphore 函数的 Milliseconds 参数只能是 INFINITE,PsReleaseSemaphore 函数的 ReleaseCount 参数只能是 1。现在要求同时修改PsWaitForSemaphore 函数和 PsReleaseSemaphore 函数中的代码,使这两个参数能够真正起到作用,使信号量对象支持等待超时唤醒功能和批量释放功能。实现方法:修改 PsWaitForSemaphore 函数:对于支持等待超时唤醒功能的信号量,其计
46、数值只能是大于等于 0。当计数值大于 0 时,表示信号量为 signaled 状态;当计数值等于 0 时,表示信号量为 nonsignaled 状态。所以,PsWaitForSemaphore 函数中原有的代码段Semaphore->Count-;if (Semaphore->Count < 0) PspWait(&Semaphore->WaitListHead, INFINITE);应被修改为:先用计数值和 0 比较,当计数值大于 0 时,将计数值减 1 后直接返回成功;当计数值等于 0 时,调用 PspWait 函数阻塞线程的执行(将参数 Milliseco
47、nds 做为 PspWait 函数的第二个参数,并使用 PspWait 函数的返回值做为返回值)。修改 PsReleaseSemaphore 函数:使用 ReleaseCount 做为计数器的循环体,来替换 PsReleaseSemaphore 函数中原有的代码段Semaphore->Count+;if (Semaphore->Count <= 0) PspWakeThread(&Semaphore->WaitListHead, STATUS_SUCCESS);在循环体中完成下面的工作:1. 如果被阻塞的线程数量大于等于 ReleaseCount,则循环结束后,
48、有 ReleaseCount 个线程会被唤醒,而且信号量计数的值仍然为 0;2. 如果被阻塞的线程数量(可以为 0)小于 ReleaseCount,则循环结束后,所有被阻塞的线程都会被唤醒,并且信号量的计数值ReleaseCount之前被阻塞线程的数量之前信号量的计数值。代码:对PsWaitForSemaphore的修改PsWaitForSemaphore(IN PSEMAPHORE Semaphore, IN ULONG Milliseconds) STATUS value;BOOL IntState;ASSERT(KeGetIntNesting() = 0); / 中断环境下不能调用此函数
49、。IntState = KeEnableInterrupts(FALSE); / 开始原子操作,禁止中断。/ 目前仅实现了标准记录型信号量,不支持超时唤醒功能,所以 PspWait 函数的第二个参数的值只能是 INFINITE。if (Semaphore->Count > 0) Semaphore->Count-;Status = STATUS_SUCCESS;else Status = PspWait(&Semaphore->WaitListHead, Milliseconds);KeEnableInterrupts(IntState); / 原子操作完成,恢
50、复中断。return Status; 分析:上面函数代码中加黑部分是修改的内容,首先判断信号量的值是否大于0,如果大于零将消耗一个单位的信号量,并且返回消耗成功,否则进行超时等待,并将此等待的状态输出。原代码仅仅实现了成功时的功能,未进行超时等待。对PsReleaseSemaphore 函数的修改while(i<ReleaseCount) if(ListIsEmpty(&Semaphore->WaitListHead) break; i+; PspWakeThread(&Semaphore->WaitListHead, STATUS_SUCCESS); if(
51、i>=ReleaseCount) Semaphore->Count=0; if(i<ReleaseCount) Semaphore->Count=ReleaseCount-i+(Semaphore->Count);分析:上述代码加黑部分是添加的内容,主要是唤醒超时等待的进程。当被阻塞的进程的数量小于释放数量时,判断信号量的等待队列是否为空,是空的则退出该循环,否则唤醒该进程,并且返回成功状态。如果被阻塞的线程数量(可以为 0)小于 ReleaseCount,则循环结束后,所有被阻塞的线程都会被唤醒,并且信号量的计数值ReleaseCount之前被阻塞线程的数量之前
52、信号量的计数值。对Producer函数的修改,添加以下代码:while(WAIT_TIMEOUT = WaitForSingleObject(EmptySemaphoreHandle, 300) printf("Producer wait for empty semaphore timeoutn"); 分析:该代码功能是当Empty信号量超时等待的时间超过300ms时,输出Producer wait for empty semaphore timeout,通过控制台显示可以判断超时等待是否添加成功。对Consumer函数的修改,添加一下代码:while(WAIT_TIMEO
53、UT = WaitForSingleObject(FullSemaphoreHandle, 300) printf("Consumer wait for full semaphore timeoutn");分析:添加的代码是Full信号量的超时等待,时间同样是300ms,如果等待时间查过300ms,就输出Consumer wait for full semaphore timeout,表示没有资源可以消耗测试和结果:添加完代码后,重新生成debug项目,使用修改完毕的 EOS Kernel 项目生成完全版本的 SDK 文件夹,并覆盖之前的生产者消费者应用程序项目的 SDK
54、文件夹,选择调试,运行结果如图:等待空信号量等待full信号量3 其他需要说明的问题 (1)思考在 ps/semaphore.c 文件内的 PsWaitForSemaphore 和PsReleaseSemaphore 函数中,为什么要使用原子操作? 答:在执行PsWaitForSemaphore和PsReleaseSemaphore函数的时候,不允许cpu响应外部中断,如果此时cpu响应了外部中断,会产生不可预料的结果,可能会产生死锁,无法正常完成函数的功能。 (2)绘制 ps/semaphore.c 文件内 PsWaitForSemaphore 和 PsReleaseSemaph
55、ore 函数的流程图。 答:实验三 时间片轮转调度(5分)1 实验目的和要求目的:理解进程(线程)调度的执行时机和过程,掌握调度程序实现的基本方法。要求:(1)跟踪调试EOS的线程调度程序,分析EOS基于优先级的抢占式调度的源代码;(2)修改EOS的调度程序,添加时间片轮转调度。2 完成的实验内容2.1 EOS基于优先级的抢占式调度工作过程的跟踪与源代码分析(分析EOS基于优先级的抢占式调度的核心源代码,简要阐述其实现方法;给出在本部分实验过程中完成的主要工作,包括调试、跟踪与思考等)本次实验中的核心源代码是ke/sysproc.c 文件中第 690 行的ConsoleCmdRoundRobin 函数及该函数用到的第 649 行的ThreadFunction 函数和第 642 行的 THREAD_PARAMETER 结构体,下面是ConsoleCmdRoundRobin的新建的20个优先级为8的进程的代码:/ 新建 20 个优先级为 8 的线程。关闭中断从而保证新建的线程不会
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 企业财务制度合理化建议
- 财务制度泰语怎么写
- 体育课教学安全管理制度
- 机关和企业财务制度区别
- 废旧金属业安全生产制度
- 监理保密制度及措施完善
- 沙滩车安全制度
- 锻造加热工岗前基础实操考核试卷含答案
- 野生动物产品采集加工利用工6S执行考核试卷含答案
- 铝镁粉球磨工安全文明模拟考核试卷含答案
- 物业小区控烟监督制度
- 常用Y系列电机型号参数表
- 葫芦岛九江220千伏输变电工程环评报告
- 2022年浙江纺织服装职业技术学院单招职业适应性测试试题及答案解析
- GB/T 26514-2011互叶白千层(精)油,松油烯-4-醇型茶树(精)油
- GA/T 1028.4-2017机动车驾驶人考试系统通用技术条件第4部分:道路驾驶技能考试系统
- 除灰点检技术标准
- 04第四章-火箭导弹的气动布局
- 齐鲁医学妊娠期急腹症
- 【部编版】六年级道德与法治下册全册课件
- 年龄相关性白内障课件
评论
0/150
提交评论