欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > DOCX文档下载  

    操作系统实验(1).docx

    • 资源ID:3549597       资源大小:43.59KB        全文页数:18页
    • 资源格式: DOCX        下载积分:6.99金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要6.99金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    操作系统实验(1).docx

    操作系统实验操作系统 实 验 报 告 课程名称 实验项目名称 学号 姓名 学生所在学院 实验室名称地点 操作系统实验 进程的同步 课程编号 0906553 年级 专业 指导教师 哈尔滨工程大学 计算机科学与技术学院 第五讲 进程的同步 一、实验概述 1. 实验名称 进程的同步 2. 实验目的 l 使用EOS的信号量,编程解决生产者消费者问题,理解进程同步的意义。 l 调试跟踪EOS信号量的工作过程,理解进程同步的原理。 l 修改EOS的信号量算法,使之支持等待超时唤醒功能,加深理解进程同步的原理。 3. 实验类型 验证,设计 4. 实验内容 4.1 准备实验 4.2 使用EOS的信号量解决生产者消费者问题 4.3 调试EOS信号量的工作过程 4.3.1 创建信号量 4.3.2 等待、释放信号量 4.3.2.1 等待信号量 4.3.2.2 释放信号量 4.3.2.3 等待信号量 4.3.2.4 释放信号量 4.4 修改EOS的信号量算法 二、实验环境 操作系统集成实验环境 OS Lab l EOS 操作系统 三、实验过程 1. 设计思路和流程图 1 2. 需要解决的问题及解答 (1). P143生产者在生产了13号产品后本来要继续生产14号产品,可此时生产者为什么必须等待消费者消费了4号产品后,才能生产14号产品呢?生产者和消费者是怎样使用同步对象来实现该同步过程的呢? 答:此时生产了0-13号14个产品,消费了0-3号4个产品,缓冲区都占满了。只有缓冲区有空闲生产者才能生产东西,有权向里面放东西。所以它必须等到消费者,取走产品,有空闲缓冲区时,才继续生产14号产品。 (2). P145-3.4 修改EOS的信号量算法(只看一次消费1个产品的,一次消费2个产品的可以写到实验报告中) 答:见之后部分 (3). 思考在ps/semaphore.c文件内的PsWaitForSemaphore和PsReleaseSemaphore函数中,为什么要使用原子操作? 答:原子操作要求一旦开始就要运行到结束,不能有中断。在执行等待信号量和释放信号量的时候,不允许cpu响应外部中断,所以使用原子操作。 (4). 绘制ps/semaphore.c文件内PsWaitForSemaphore和PsReleaseSemaphore函数的流程图。 PsWaitForSemaphore N 开始原子操作P操作 原子操作前关中断 Wait操作的信号执行Y P操作 P操作结束 2 Ps Release Semaphore P和V操作的信号量之N 开始原子操作V操作 原子操作前关中断 和大于缓冲队列长度 Y N P操作控制的信号量不大于0 Y 被阻塞进程量小于要释唤醒等待进程 放的信号量 N 返回“信号数目量超出范围” 释放信号量 Y 记录当前信号量的值 信号量值+1 唤醒队列中进程 返回“唤醒成功” 等待队列为空 N Y ps/semaphore.c文件 #include "psp.h" VOID PsInitializeSemaphore( IN PSEMAPHORE Semaphore, IN LONG InitialCount, 结束 3. 主要数据结构、实现代码及其说明 3 IN LONG MaximumCount) /*+ 功能描述: 初始化信号量结构体。 参数: Semaphore - 要初始化的信号量结构体指针。 InitialCount - 信号量的初始值,不能小于 0 且不能大于 MaximumCount。 MaximumCount - 信号量的最大值,必须大于 0。 返回值:无。 -*/ ASSERT(InitialCount >= 0 && InitialCount <= MaximumCount && MaximumCount > 0); Semaphore->Count = InitialCount; Semaphore->MaximumCount = MaximumCount; ListInitializeHead(&Semaphore->WaitListHead); STATUS PsWaitForSemaphore( IN PSEMAPHORE Semaphore, IN ULONG Milliseconds) /*+ 功能描述: 信号量的 Wait 操作。 参数: Semaphore - Wait 操作的信号量对象。 Milliseconds - 等待超时上限,单位毫秒。 返回值: STATUS_SUCCESS。 当你修改信号量使之支持超时唤醒功能后,如果等待超时,应该返回 STATUS_TIMEOUT。 -*/ 4 BOOL IntState; STATUS flag; ASSERT(KeGetIntNesting = 0); / 中断环境下不能调用此函数。 IntState = KeEnableInterrupts(FALSE); / 开始原子操作,禁止中断。 / 目前仅实现了标准记录型信号量,不支持超时唤醒功能,所以 PspWait 函数 / 的第二个参数的值只能是 INFINITE。 if (Semaphore->Count>0) else flag=PspWait(&Semaphore->WaitListHead, Milliseconds); Semaphore->Count-; flag=STATUS_SUCCESS; KeEnableInterrupts(IntState); / 原子操作完成,恢复中断。 return flag; STATUS PsReleaseSemaphore( IN PSEMAPHORE Semaphore, IN LONG ReleaseCount, OUT PLONG PreviousCount ) STATUS Status; BOOL IntState; IntState = KeEnableInterrupts(FALSE); / 开始原子操作,禁止中断。 if (Semaphore->Count + ReleaseCount > Semaphore->MaximumCount) Status = STATUS_SEMAPHORE_LIMIT_EXCEEDED; else / 记录当前的信号量的值。 if (NULL != PreviousCount) *PreviousCount = Semaphore->Count; 5 int mm=Semaphore->Count;/ 目前仅实现了标准记录型信号量,每执行一次信号量的释放操作 / 只能使信号量的值增加 1。 while (!ListIsEmpty(&Semaphore->WaitListHead)&&(ReleaseCount) Semaphore->Count=mm+ReleaseCount;/ 可能有线程被唤醒,执行线程调度。 Status = STATUS_SUCCESS; PspWakeThread(&Semaphore->WaitListHead, STATUS_SUCCESS); PspThreadSchedule; ReleaseCount-; KeEnableInterrupts(IntState); / 原子操作完成,恢复中断。 return Status; POBJECT_TYPE PspSemaphoreType = NULL;/ 用于初始化 semaphore 结构体的参数结构体。 typedef struct _SEM_CREATE_PARAM LONG InitialCount; LONG MaximumCount; SEM_CREATE_PARAM, *PSEM_CREATE_PARAM;/semaphore 对象的构造函数,在创建新 semaphore 对象时被调用。 VOID PspOnCreateSemaphoreObject( IN PVOID SemaphoreObject, IN ULONG_PTR CreateParam) PsInitializeSemaphore( (PSEMAPHORE)SemaphoreObject, (PSEM_CREATE_PARAM)CreateParam)->InitialCount, (PSEM_CREATE_PARAM)CreateParam)->MaximumCount ); / semaphore 对象类型的初始化函数。 VOID PspCreateSemaphoreObjectType( 6 VOID) STATUS Status; OBJECT_TYPE_INITIALIZER Initializer; Initializer.Create = PspOnCreateSemaphoreObject; Initializer.Delete = NULL; Initializer.Wait = (OB_WAIT_METHOD)PsWaitForSemaphore; Initializer.Read = NULL; Initializer.Write = NULL; Status = ObCreateObjectType("SEMAPHORE", &Initializer, &PspSemaphoreType); if (!EOS_SUCCESS(Status) / semaphore 对象的构造函数。 STATUS PsCreateSemaphoreObject( IN LONG InitialCount, IN LONG MaximumCount, IN PSTR Name, OUT PHANDLE SemaphoreHandle ) STATUS Status; PVOID SemaphoreObject; SEM_CREATE_PARAM CreateParam; if(InitialCount < 0 | MaximumCount <= 0 | InitialCount > MaximumCount) return STATUS_INVALID_PARAMETER; KeBugCheck("Failed to create semaphore object type!"); / 创建信号量对象。 CreateParam.InitialCount = InitialCount; CreateParam.MaximumCount = MaximumCount; Status = ObCreateObject( PspSemaphoreType, 7 Name, sizeof(SEMAPHORE), (ULONG_PTR)&CreateParam, &SemaphoreObject); if (!EOS_SUCCESS(Status) Status = ObCreateHandle(SemaphoreObject, SemaphoreHandle); if (!EOS_SUCCESS(Status) return Status; / semaphore 对象的 signal 操作函数。 STATUS PsReleaseSemaphoreObject( IN HANDLE Handle, IN LONG ReleaseCount, IN PLONG PreviousCount) STATUS Status; PSEMAPHORE Semaphore; if (ReleaseCount < 1) return STATUS_INVALID_PARAMETER; ObDerefObject(SemaphoreObject); return Status; / 由 semaphore 句柄得到 semaphore 对象的指针。 Status = ObRefObjectByHandle(Handle, PspSemaphoreType, (PVOID*)&Semaphore); if (EOS_SUCCESS(Status) return Status; 8 Status = PsReleaseSemaphore(Semaphore, ReleaseCount, PreviousCount); ObDerefObject(Semaphore); 4. 程序运行时的初值和运行结果 4.1 准备实验 按照下面的步骤准备本次实验: 1. 启动OS Lab。 2. 新建一个EOS Kernel项目。 3. 生成EOS Kernel项目,从而在该项目文件夹中生成SDK文件夹。 4. 新建一个EOS应用程序项目。 5. 使用在第3步生成的SDK文件夹覆盖EOS应用程序项目文件夹中的SDK文件夹。 4.2 使用EOS的信号量解决生产者消费者问题 在本实验文件夹中,提供了使用EOS的信号量解决生产者消费者问题的参考源代码文件pc.c。使用OS Lab打开此文件 按照下面的步骤查看生产者消费者同步执行的过程: 1. 使用pc.c文件中的源代码,替换之前创建的EOS应用程序项目中EOSApp.c文件内的源代码。 9 2. 按F7生成修改后的EOS应用程序项目。 3. 按F5启动调试。OS Lab会首先弹出一个调试异常对话框。 4. 在调试异常对话框中选择“否”,继续执行。 5. 立即激活虚拟机窗口查看生产者消费者同步执行的过程。 10 6. 待应用程序执行完毕后,结束此次调试。 4.3 调试EOS信号量的工作过程 4.3.1 创建信号量 信号量结构体中的各个成员变量是由API函数CreateSemaphore的对应参数初始化的,查看main函数中创建Empty和Full信号量使用的参数有哪些不同,又有哪些相同,思考其中的原因。 按照下面的步骤调试信号量创建的过程: 1. 按F5启动调试EOS应用项目。OS Lab会首先弹出一个调试异常对话框。 2. 在调试异常对话框中选择“是”,调试会中断。 3. 在main函数中创建Empty信号量的代码行 EmptySemaphoreHandle = CreateSemaphore(BUFFER_SIZE, BUFFER_SIZE, NULL); 添加一个断点。 4. 按F5继续调试,到此断点处中断。 5. 按F11调试进入CreateSemaphore函数。可以看到此API函数只是调用了EOS内核中的PsCreateSemaphoreObject函数来创建信号量对象。 6. 按F11调试进入semaphore.c文件中的PsCreateSemaphoreObject函数。在此函数中,会在EOS内核管理的内存中创建一个信号量对象,而初始化信号量对象中各个成员的操作是在PsInitializeSemaphore函数中完成的。 7. 在semaphore.c文件的顶部查找到PsInitializeSemaphore函数的定义,在此函数的第一行代码处添加一个断点。 11 8. 按F5继续调试,到断点处中断。观察PsInitializeSemaphore函数中用来初始化信号量结构体成员的值,应该和传入CreateSemaphore函数的参数值是一致的。 9. 按F10单步调试PsInitializeSemaphore函数执行的过程,查看信号量结构体被初始化的过程。打开“调用堆栈”窗口,查看函数的调用层次。 4.3.2 等待、释放信号量 4.3.2.1 等待信号量 生产者和消费者刚开始执行时,用来放产品的缓冲区都是空的,所以生产者在第一次调用WaitForSingleObject函数等待Empty信号量时,应该不需要阻塞就可以立即返回。按照下面的步骤调试: 1. 删除所有的断点。 2. 在eosapp.c文件的Producer函数中,等待Empty信号量的代码行 WaitForSingleObject(EmptySemaphoreHandle, INFINITE); 添加一个断点。 12 3. 按F5继续调试,到断点处中断。 4. WaitForSingleObject 函数最终会调用内核中的PsWaitForSemaphore函数完成等待操作。所以,在semaphore.c文件中PsWaitForSemaphore函数的第一行添加一个断点。 5. 按F5继续调试,到断点处中断。 6. 按F10单步调试,直到完成PsWaitForSemaphore函数中的所有操作。可以看到此次执行并没有进行等待,只是将Empty信号量的计数减少了1就返回了。 4.3.2.2 释放信号量 1. 删除所有的断点。 2. 在eosapp.c文件的Producer函数中,释放Full信号量的代码行 ReleaseSemaphore(FullSemaphoreHandle, 1, NULL); 添加一个断点。 13 3. 按F5继续调试,到断点处中断。 4. 按F11调试进入ReleaseSemaphore函数。 5. 继续按F11调试进入PsReleaseSemaphoreObject函数。 6. 先使用F10单步调试,当黄色箭头指向第269行时使用F11单步调试,进入PsReleaseSemaphore函数。 7. 按F10单步调试,直到完成PsReleaseSemaphore函数中的所有操作。可以看到此次执行没有唤醒其它线程,只是将Full信号量的计数增加了1。 生产者线程通过等待Empty信号量使空缓冲区数量减少了1,通过释放Full信号量使满缓冲区数量增加了1,这样就表示生产者线程生产了一个产品并占用了一个缓冲区。 4.3.2.3 等待信号量 由于开始时生产者线程生产产品的速度较快,而消费者线程消费产品的速度较慢,所以当缓冲池中所有的缓冲区都被产品占用时,生产者在生产新的产品时就会被阻塞,下面调试这种情况。 1. 结束之前的调试。 2. 删除所有的断点。 14 3. 按F5重新启动调试。OS Lab会首先弹出一个调试异常对话框。 4. 在调试异常对话框中选择“是”,调试会中断。 5. 在semaphore.c文件中的PsWaitForSemaphore函数的 PspWait(&Semaphore->WaitListHead, INFINITE); 代码行添加一个断点。 6. 按F5继续调试,并立即激活虚拟机窗口查看输出。开始时生产者、消费者都不会被信号量阻塞,同步执行一段时间后才在断点处中断。 7. 中断后,查看“调用堆栈”窗口,有Producer函数对应的堆栈帧,说明此次调用是从生产者线程函数进入的。 15 8. 在“调用堆栈”窗口中双击Producer函数所在的堆栈帧,绿色箭头指向等待Empty信号量的代码行,查看Producer函数中变量i的值为14,表示生产者线程正在尝试生产14号产品。 9. 在调用堆栈窗口中双击PsWaitForSemaphore函数的堆栈帧,查看Empty信号量计数的值为-1,所以会调用PspWait函数将生产者线程放入Empty信号量的等待队列中进行等待。 10. 激活虚拟机窗口查看输出的结果。生产了从0到13的14个产品,但是只消费了从0到3的4个产品,所以缓冲池中的10个缓冲区就都被占用了,这与之前调试的结果是一致的。 4.3.2.4 释放信号量 只有当消费者线程从缓冲池中消费了一个产品,从而产生一个空缓冲区后,生产者线程才会被唤醒并继续生产14号产品。可以按照下面的步骤调试: 1. 删除所有断点。 2. 在eosapp.c文件的Consumer函数中,释放Empty信号量的代码行 ReleaseSemaphore(EmptySemaphoreHandle, 1, NULL); 添加一个断点。 16 3. 按F5继续调试,到断点处中断。 4. 查看Consumer函数中变量i的值为4,说明已经消费了4号产品。 5. 按照3.3.2.2中的方法使用F10和F11调试进入PsReleaseSemaphore函数。 6. 查看PsReleaseSemaphore函数中Empty信号量计数的值为-1,和生产者线程被阻塞时的值是一致的。 7. 按F10单步调试PsReleaseSemaphore函数,直到在代码行 PspWakeThread(&Semaphore->WaitListHead, STATUS_SUCCESS); 处中断。此时Empty信号量计数的值已经由-1增加为了0,需要调用PspWakeThread函数唤醒阻塞在Empty信号量等待队列中的生产者线程,然后调用PspSchedule函数执行调度,这样生产者线程就得以继续执行。 按照下面的步骤验证生产者线程被唤醒后,是从之前被阻塞时的状态继续执行的: 1. 在semaphore.c文件中PsWaitForSemaphore函数的最后一行代码处添加一个断点。 17 2. 按F5继续调试,在断点处中断。 3. 查看PsWaitForSemaphore函数中Empty信号量计数的值为0,和生产者线程被唤醒时的值是一致的。 4. 在“调用堆栈”窗口中可以看到是由Producer函数进入的。激活Producer函数的堆栈帧,查看Producer函数中变量i的值为14,表明之前被阻塞的、正在尝试生产14号产品的生产者线程已经从PspWait函数返回并继续执行了。 5. 结束此次调试。 4.4 修改EOS的信号量算法 4.4.1 要求 在目前EOS Kernel项目的ps/semaphore.c文件中,PsWaitForSemaphore函数的Milliseconds参数只能是INFINITE,PsReleaseSemaphore函数的ReleaseCount参数只能是1。现在要求同时修改PsWaitForSemaphore函数和PsReleaseSemaphore函数中的代码,使这两个参数能够真正起到作用,使信号量对象支持等待超时唤醒功能和批量释放功能。 4.4.2 提示 修改PsWaitForSemaphore函数时要注意: l 对于支持等待超时唤醒功能的信号量,其计数值只能是大于等于0。当计数值大于0时,表示信号量为signaled状态;当计数值等于0时,表示信号量为nonsignaled状态。所以,PsWaitForSemaphore函数中原有的代码段 Semaphore->Count-; if (Semaphore->Count < 0) PspWait(&Semaphore->WaitListHead, INFINITE); 应被修改为:先用计数值和0比较,当计数值大于0时,将计数值减1后直接返回成功;当计数值等于0时,调用PspWait函数阻塞线程的执行。 l 在函数开始定义一个STATUS类型的变量,用来保存不同情况下的返回值,并在函数最后返回此变量的值。绝不能在原子操作的中途返回! 18 l 在EOS Kernel项目ps/sched.c文件的第190行查看PspWait函数的说明和源代码。 修改PsReleaseSemaphore函数时要注意: l 编写一个使用ReleaseCount做为计数器的循环体,来替换PsReleaseSemaphore函数中原有的代码段 Semaphore->Count+; if (Semaphore->Count <= 0) PspWakeThread(&Semaphore->WaitListHead, STATUS_SUCCESS); l 在循环体中完成下面的工作: 1. 如果被阻塞的线程数量大于等于ReleaseCount,则循环结束后,有ReleaseCount个线程会被唤醒,而且信号量计数的值仍然为0; 2. 如果被阻塞的线程数量小于ReleaseCount,则循环结束后,所有被阻塞的线程都会被唤醒,并且信号量的计数值ReleaseCount之前被阻塞线程的数量之前信号量的计数值。 l 在EOS Kernel项目ps/sched.c文件的第294行查看PspWakeThread函数的说明和源代码 l 在循环的过程中可以使用宏定义函数ListIsEmpty判断信号量的等待队列是否为空,例如 ListIsEmpty(&Semaphore->WaitListHead) 可以在EOS Kernel项目inc/rtl.h文件的第113行查看此宏定义的源代码。 4.4.3 测试方法 修改完毕后,可以按照下面的方法进行测试: 1. 使用修改完毕的EOS Kernel项目生成完全版本的SDK文件夹,并覆盖之前的生产者消费者应用程序项目的SDK文件夹。 2. 按F5调试执行原有的生产者消费者应用程序项目,结果必须仍然与图13-2一致。如果有错误,可以调试内核代码来查找错误,然后在内核项目中修改,并重复步骤1。 3. 将Producer函数中等待Empty信号量的代码行 WaitForSingleObject(EmptySemaphoreHandle, INFINITE); 替换为 while(WAIT_TIMEOUT = WaitForSingleObject(EmptySemaphoreHandle, 300) printf("Producer wait for empty semaphore timeoutn"); 4. 将Consumer函数中等待Full信号量的代码行 WaitForSingleObject(FullSemaphoreHandle, INFINITE); 替换为 while(WAIT_TIMEOUT = WaitForSingleObject(FullSemaphoreHandle, 300) printf("Consumer wait for full semaphore timeoutn"); 5. 启动调试新的生产者消费者项目,查看在虚拟机中输出的结果,验证信号量超时等待功能是否能够正常执行。如果有错误,可以调试内核代码来查找错误,然后在内核项目中修改,并重复步骤1。 6. 如果超时等待功能已经能够正常执行,可以考虑将消费者线程修改为一次消费两个产品,来测试ReleaseCount参数是否能够正常使用。使用实验文件夹中NewConsumer.c文件中的Consumer函数替换原有的Consumer函数。 19 20 四、实验体会 通过这次实验,我加深了对于进程同步算法的理解,以及对书上的消费者生产者模型有了更深层的认识,并且留下了新的印象。这次实验提高了我的编程能力和各方面动手能力,虽然在编程过程中出现了些许错误,但是在周围同学的帮助下及时改正了错误,本次试验结果总体来讲较为成功,并且让我感受到进程相关内容编程的风格和方法。 21

    注意事项

    本文(操作系统实验(1).docx)为本站会员(牧羊曲112)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开