ImageVerifierCode 换一换
格式:DOCX , 页数:18 ,大小:222KB ,
资源ID:6934016      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6934016.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(哈尔滨工程大学操作系统 实验四进程的同步.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

哈尔滨工程大学操作系统 实验四进程的同步.docx

1、哈尔滨工程大学操作系统 实验四进程的同步操作系统实 验 报 告课程名称操作系统实验课程编号实验项目名称进程的同步学号20年级2013姓名徐大亮专业软件工程学生所在学院软件学院指导教师刘 刚实验室名称地点计算机软件第二实验室 21#427 哈尔滨工程大学软件学院第四讲 进程的同步一、实验概述1. 实验名称:进程的同步2. 实验目的:(1)使用 EOS 的信号量,编程解决生产者消费者问题,理解进程同步的意义。(2)调试跟踪 EOS 信号量的工作过程,理解进程同步的原理。(3)修改 EOS 的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。3. 实验类型:验证设计 4. 实

2、验内容 1) 准备实验 2) 使用 EOS 的信号量解决生产者消费者问题 3) 调试 EOS 信号量的工作过程4)修改 EOS 的信号量算法二、实验环境操作系统:windows xp编译器:Bochs 模拟器语言:C语言工具:OSLAB三、实验过程1 准备实验 按照下面的步骤准备本次实验: 1. 启动 OS Lab。 2. 新建一个 EOS Kernel项目。 3. 生成 EOS Kernel项目,从而在该项目文件夹中生成SDK 文件夹。 4. 新建一个 EOS应用程序项目。 5. 使用在第3步生成的SDK文件夹覆盖EOS应用程序项目文件夹中的SDK文件夹。 2 使用EOS 的信号量解决生产者

3、消费者问题 在本实验文件夹中,提供了使用EOS的信号量解决生产者消费者问题的参考源代码文件pc.c。使用OS Lab打开此文件(将文件拖动到OS Lab窗口中释放即可打开),仔细阅读此文件中的源代码和注释,各个函数的流程图可以参见图 13-1。思考在两个线程函数(Producer 和 Consumer)中,哪些是临界资源?哪些代码是临界区?哪些代码是进入临界区?哪些代码是退出临界区?进入临界区和退出临界区的代码是否成对出现? 按照下面的步骤查看生产者消费者同步执行的过程: 1. 使用 pc.c文件中的源代码,替换之前创建的EOS 应用程序项目中EOSApp.c文件内的源代码。 2. 按 F7生

4、成修改后的EOS应用程序项目。 3. 按F5启动调试。OS Lab会首先弹出一个调试异常对话框。 4. 在调试异常对话框中选择“否”,继续执行。 5. 立即激活虚拟机窗口查看生产者消费者同步执行的过程,如图13-2。 6. 待应用程序执行完毕后,结束此次调试。3 调试EOS 信号量的工作过程 3.1 创建信号量 信号量结构体 (SEMAPHORE) 中的各个成员变量是由API 函数 CreateSemaphore的对应参数初始化的,查看 main函数中创建Empty和Full信号量使用的参数有哪些不同,又有哪些相同,思考其中的原因。 按照下面的步骤调试信号量创建的过程: 1. 按 F5启动调试

5、EOS应用项目。OS Lab会首先弹出一个调试异常对话框。 2. 在调试异常对话框中选择“是”,调试会中断。 3. 在 main 函数中创建Empty信号量的代码行(第77行) EmptySemaphoreHandle = CreateSemaphore(BUFFER_SIZE, BUFFER_SIZE, NULL); 添加一个断点。 4. 按 F5继续调试,到此断点处中断。 5. 按 F11 调试进入 CreateSemaphore 函数。可以看到此 API 函数只是调用了 EOS 内核中的PsCreateSemaphoreObject函数来创建信号量对象。 6. 按 F11 调试进入 se

6、maphore.c 文件中的 PsCreateSemaphoreObject 函数。在此函数中,会在 EOS内核管理的内存中创建一个信号量对象(分配一块内存),而初始化信号量对象中各个成员的操作是在 PsInitializeSemaphore函数中完成的。 7. 在 semaphore.c文件的顶部查找到PsInitializeSemaphore函数的定义(第 19 行),在此函数的第一行(第39行)代码处添加一个断点。 8. 按 F5继续调试,到断点处中断。观察PsInitializeSemaphore函数中用来初始化信号量结构体成员的值,应该和传入CreateSemaphore函数的参数值

7、是一致的。 9. 按 F10 单步调试 PsInitializeSemaphore 函数执行的过程,查看信号量结构体被初始化的过程。打开“调用堆栈”窗口,查看函数的调用层次。 3.2 等待、释放信号量 3.2.1 等待信号量(不阻塞) 生产者和消费者刚开始执行时,用来放产品的缓冲区都是空的,所以生产者在第一次调用WaitForSingleObject函数等待Empty 信号量时,应该不需要阻塞就可以立即返回。按照下面的步骤调试: 1. 删除所有的断点(防止有些断点影响后面的调试)。 2. 在 eosapp.c文件的Producer函数中,等待Empty信号量的代码行(第144行) WaitFo

8、rSingleObject(EmptySemaphoreHandle, INFINITE); 添加一个断点。 3. 按 F5继续调试,到断点处中断。 4. WaitForSingleObject 函数最终会调用内核中的PsWaitForSemaphore函数完成等待操作。所以,在 semaphore.c文件中 PsWaitForSemaphore函数的第一行(第68行)添加一个断点。 5. 按F5继续调试,到断点处中断。 6. 按 F10 单步调试,直到完成 PsWaitForSemaphore 函数中的所有操作。可以看到此次执行并没有进行等待,只是将Empty信号量的计数减少了1(由10变为

9、了 9)就返回了。 3.2.2 释放信号量(不唤醒) 1. 删除所有的断点(防止有些断点影响后面的调试)。 2. 在 eosapp.c文件的Producer函数中,释放Full信号量的代码行(第152行) ReleaseSemaphore(FullSemaphoreHandle, 1, NULL); 添加一个断点。 3. 按 F5继续调试,到断点处中断。 4. 按 F11调试进入ReleaseSemaphore函数。 5. 继续按 F11调试进入PsReleaseSemaphoreObject函数。 6. 先使用 F10单步调试,当黄色箭头指向第269行时使用 F11单步调试,进入PsRele

10、aseSemaphore函数。 7. 按 F10 单步调试,直到完成 PsReleaseSemaphore 函数中的所有操作。可以看到此次执行没有唤醒其它线程(因为此时没有线程在 Full 信号量上被阻塞),只是将 Full 信号量的计数增加了 1(由 0变为了 1)。 生产者线程通过等待Empty信号量使空缓冲区数量减少了1,通过释放Full信号量使满缓冲区数量增加了 1,这样就表示生产者线程生产了一个产品并占用了一个缓冲区。 3.2.3 等待信号量(阻塞) 由于开始时生产者线程生产产品的速度较快,而消费者线程消费产品的速度较慢,所以当缓冲池中所有的缓冲区都被产品占用时,生产者在生产新的产品

11、时就会被阻塞,下面调试这种情况。 1. 结束之前的调试。 2. 删除所有的断点。 3. 按 F5重新启动调试。OS Lab会首先弹出一个调试异常对话框。 4. 在调试异常对话框中选择“是”,调试会中断。 5. 在 semaphore.c文件中的PsWaitForSemaphore函数的 PspWait(&Semaphore-WaitListHead, INFINITE); 代码行(第78行)添加一个断点。 6. 按 F5继续调试,并立即激活虚拟机窗口查看输出。开始时生产者、消费者都不会被信号量阻塞,同步执行一段时间后才在断点处中断。 7. 中断后,查看“调用堆栈”窗口,有 Producer 函

12、数对应的堆栈帧,说明此次调用是从生产者线程函数进入的。 8. 在“调用堆栈”窗口中双击 Producer 函数所在的堆栈帧,绿色箭头指向等待 Empty 信号量的代码行,查看Producer函数中变量i 的值为14,表示生产者线程正在尝试生产14 号产品。 9. 在“调用堆栈”窗口中双击 PsWaitForSemaphore 函数的堆栈帧,查看 Empty 信号量计数(Semaphore-Count)的值为-1,所以会调用PspWait函数将生产者线程放入Empty信号量的等待队列中进行等待(让出CPU)。 10. 激活虚拟机窗口查看输出的结果。生产了从0到13的14个产品,但是只消费了从0到

13、 3的 4个产品,所以缓冲池中的10个缓冲区就都被占用了,这与之前调试的结果是一致的。 3.2.4 释放信号量(唤醒) 只有当消费者线程从缓冲池中消费了一个产品,从而产生一个空缓冲区后,生产者线程才会被唤醒并继续生产 14号产品。可以按照下面的步骤调试: 1. 删除所有断点。 2. 在 eosapp.c文件的Consumer函数中,释放Empty信号量的代码行(第180行) ReleaseSemaphore(EmptySemaphoreHandle, 1, NULL); 添加一个断点。 3. 按 F5继续调试,到断点处中断。 4. 查看Consumer函数中变量i 的值为4,说明已经消费了4

14、号产品。 5. 按照3.3.2.2中的方法使用F10和 F11 调试进入PsReleaseSemaphore函数。 6. 查看 PsReleaseSemaphore 函数中 Empty 信号量计数(Semaphore-Count)的值为-1,和生产者线程被阻塞时的值是一致的。 7. 按 F10单步调试PsReleaseSemaphore函数,直到在代码行(第132行) PspWakeThread(&Semaphore-WaitListHead, STATUS_SUCCESS); 处中断。此时Empty信号量计数的值已经由-1 增加为了0,需要调用PspWakeThread函数唤醒阻塞在 Emp

15、ty 信号量等待队列中的生产者线程(放入就绪队列中),然后调用 PspSchedule 函数执行调度,这样生产者线程就得以继续执行。 按照下面的步骤验证生产者线程被唤醒后,是从之前被阻塞时的状态继续执行的: 1. 在 semaphore.c文件中 PsWaitForSemaphore函数的最后一行(第 83 行)代码处添加一个断点。 2. 按 F5继续调试,在断点处中断。 3. 查看PsWaitForSemaphore函数中 Empty 信号量计数(Semaphore-Count)的值为0,和生产者线程被唤醒时的值是一致的。 4. 在“调用堆栈”窗口中可以看到是由Producer函数进入的。激

16、活 Producer函数的堆栈帧,查看Producer函数中变量i的值为 14,表明之前被阻塞的、正在尝试生产14号产品的生产者线程已经从 PspWait函数返回并继续执行了。 5. 结束此次调试。 4. 修改 EOS 的信号量算法1)根据文档修改的代码如下:PsWaitForSemaphore函数代码:STATUSPsWaitForSemaphore( IN PSEMAPHORE Semaphore, IN ULONG Milliseconds )/*+功能描述: 信号量的 Wait 操作(P 操作)。参数: Semaphore - Wait 操作的信号量对象。 Milliseconds -

17、 等待超时上限,单位毫秒。返回值: STATUS_SUCCESS。 当你修改信号量使之支持超时唤醒功能后,如果等待超时,应该返回 STATUS_TIMEOUT。-*/ BOOL IntState; STATUS Status; ASSERT(KeGetIntNesting() = 0); / 中断环境下不能调用此函数。 IntState = KeEnableInterrupts(FALSE); / 开始原子操作,禁止中断。 / / 目前仅实现了标准记录型信号量,不支持超时唤醒功能,所以 PspWait 函数 / 的第二个参数的值只能是 INFINITE。 / if (Semaphore-Cou

18、nt 0) Semaphore-Count-; Status = STATUS_SUCCESS; else Status=PspWait(&Semaphore-WaitListHead, Milliseconds); KeEnableInterrupts(IntState); / 原子操作完成,恢复中断。 return Status;PsReleaseSemaphore代码如下:STATUSPsReleaseSemaphore( IN PSEMAPHORE Semaphore, IN LONG ReleaseCount, OUT PLONG PreviousCount )/*+功能描述: 信号

19、量的 Signal 操作(V 操作)。参数: Semaphore - Wait 操作的信号量对象。 ReleaseCount - 信号量计数增加的数量。当前只能为 1。当你修改信号量使之支持 超时唤醒功能后,此参数的值能够大于等于 1。 PreviousCount - 返回信号量计数在增加之前的值。返回值: 如果成功释放信号量,返回 STATUS_SUCCESS。-*/ STATUS Status; BOOL IntState; IntState = KeEnableInterrupts(FALSE); / 开始原子操作,禁止中断。 if (Semaphore-Count + ReleaseC

20、ount Semaphore-MaximumCount) Status = STATUS_SEMAPHORE_LIMIT_EXCEEDED; else / / 记录当前的信号量的值。 / if (NULL != PreviousCount) *PreviousCount = Semaphore-Count; / / 目前仅实现了标准记录型信号量,每执行一次信号量的释放操作 / 只能使信号量的值增加 1。 / for(Semaphore-Count += ReleaseCount; Semaphore-Count0&!ListIsEmpty(&Semaphore-WaitListHead); S

21、emaphore-Count-) PspWakeThread(&Semaphore-WaitListHead, STATUS_SUCCESS); PspThreadSchedule(); /Semaphore-Count+; /*if (Semaphore-Count WaitListHead, STATUS_SUCCESS); */ / / 可能有线程被唤醒,执行线程调度。 / /PspThreadSchedule(); Status = STATUS_SUCCESS; KeEnableInterrupts(IntState); / 原子操作完成,恢复中断。 return Status;结果

22、如下:2)根据测试要求1将原来的代码更改为如下:/ 生产者线程函数。/ULONG Producer(PVOID Param) int i; int InIndex = 0; for (i = 0; i PRODUCT_COUNT; i+) WaitForSingleObject(EmptySemaphoreHandle, INFINITE); WaitForSingleObject(MutexHandle, INFINITE); printf(Produce a %dn, i); BufferInIndex = i; InIndex = (InIndex + 1) % BUFFER_SIZE;

23、 ReleaseMutex(MutexHandle); ReleaseSemaphore(FullSemaphoreHandle, 3, NULL); / / 休息一会。每 500 毫秒生产一个数。 / Sleep(500); return 0;/ 消费者线程函数。/ULONG Consumer(PVOID Param) int i; int OutIndex = 0; for (i = 0; i PRODUCT_COUNT; i+) WaitForSingleObject(FullSemaphoreHandle, INFINITE); WaitForSingleObject(MutexHan

24、dle, INFINITE); printf(tttConsume a %dn, BufferOutIndex); OutIndex = (OutIndex + 1) % BUFFER_SIZE; ReleaseMutex(MutexHandle); ReleaseSemaphore(EmptySemaphoreHandle, 3, NULL); / / 休息一会儿。让前 10 个数的消费速度比较慢,后面的较快。 / if (i 10) Sleep(2000); else Sleep(100); return 0;执行结果如下图所示:3)将cunsumer的函数替换,测试一次消费两个产品的情况

25、,代码如下:/ 消费者线程函数。/ULONG Consumer(PVOID Param)4) int i; int OutIndex = 0; for (i = 0; i PRODUCT_COUNT; i += 2) while(WAIT_TIMEOUT = WaitForSingleObject(FullSemaphoreHandle, 300) printf(Consumer wait for full semaphore timeoutn); while(WAIT_TIMEOUT = WaitForSingleObject(FullSemaphoreHandle, 300) printf

26、(Consumer wait for full semaphore timeoutn); WaitForSingleObject(MutexHandle, INFINITE); printf(tttConsume a %dn, BufferOutIndex); OutIndex = (OutIndex + 1) % BUFFER_SIZE; printf(tttConsume a %dn, BufferOutIndex); OutIndex = (OutIndex + 1) % BUFFER_SIZE; ReleaseMutex(MutexHandle); ReleaseSemaphore(E

27、mptySemaphoreHandle, 2, NULL); / / 休息一会儿。让前 14 个数的消费速度比较慢,后面的较快。 / if (i 14) Sleep(2000); else Sleep(100); return 0;操作结果如下:5.思考题1) PsWaitForSemaphore函数的流程图:PsReleaseSemaphore函数的流程图: 6.思考题P143,生产者在生产了13号产品后本来要继续生产14号产品,可此时生产者为什么必须等待消费者消费了4号产品后,才能生产14号产品呢?生产者和消费者是怎样使用同步对象来实现该同步过程的呢?答:因为此时生产者生产了14个产品,而消费者消费了4个产品,即缓冲区有10个资源,已经满了,所以只能等待4号产品消费了才可以继续生产。四实验体会实验过程中遇到的问题主要是在找到需要改的两个函数的过程,开始始终在app工程中修改sdk代码,导致无论如何编译都不能获得更改的效果,等我一步步寻找后,最终发现该问题,并成功修改函数,让我对整个进程的创建过程,以及进程的等待和释放有了更好地了解,对了大于300ms等待有了较深的理解,并能够实现同时释放多个资源的效果,对操作系统的流程,有了更深地理解。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1