操作系统实验四 进程的同步Word格式.docx
- 文档编号:20732846
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:23
- 大小:476.96KB
操作系统实验四 进程的同步Word格式.docx
《操作系统实验四 进程的同步Word格式.docx》由会员分享,可在线阅读,更多相关《操作系统实验四 进程的同步Word格式.docx(23页珍藏版)》请在冰豆网上搜索。
3.实验类型(验证、设计)
验证
4.实验内容
1).准备实验
2).使用EOS的信号量解决生产者-消费者问题
3).调试EOS信号量的工作过程
①创建信号量
②等待释放信号量
③等待信号量(不阻塞)
④释放信号量(不唤醒)
⑤等待信号量(阻塞)
⑥释放信号量(唤醒)
4).修改EOS的信号量算法
在目前EOSKernel项目的ps/semaphore.c文件中,PsWaitForSemaphore函数的Milliseconds参数只能是INFINITE,PsReleaseSemaphore函数的ReleaseCount参数只能是1。
现在要求同时修改PsWaitForSemaphore函数和PsReleaseSemaphore函数中的代码,使这两个参数能够真正起到作用,使信号量对象支持等待超时唤醒功能和批量释放功能。
二、实验环境
操作系统:
windowsxp
编译环境:
OSLab
三、实验过程
1.设计思路和流程图
图3-1.整体试验流程图
图3-2.Main函数流程图、生产者消费、消费者流程图
2.需要解决的问题及解答
(1).思考在ps/semaphore.c文件内的PsWaitForSemaphore和PsReleaseSemaphore函数中,为什么要使用原子操作?
答:
在执行等待信号量和释放信号量的时候,是不允许cpu响应外部中断的,如果此时cpu响应了外部中断,会产生不可预料的结果,无法正常完成原子操作。
(2).绘制ps/semaphore.c文件内PsWaitForSemaphore和PsReleaseSemaphore函数的流程图。
1).PsWaitForSemaphore函数流程图。
2).PsReleaseSemaphore函数流程图
(3).P143生产者在生产了13号产品后本来要继续生产14号产品,可此时生产者为什么必须等待消费者消费了4号产品后,才能生产14号产品呢?
生产者和消费者是怎样使用同步对象来实现该同步过程的呢?
这是因为临界资源的限制。
缓冲区只有十个空间,现在消费比生产慢,此时分别装了4到13号产品,而消费者只消费了3个。
此时装入产品与产品的存储空间成为直接相互制约关系,再消费者消费了下一个产品之前生产者不能继续装入。
因此,可解释生产者为什么必须等待消费者消费了4号产品后才能生产14号产品。
(4).根据本实验3.3.2节中设置断点和调试的方法,自己设计一个类似的调试方案来验证消费者线程在消费24号产品时会被阻塞,直到生产者线程生产了24号产品后,消费者线程才被唤醒并继续执行的过程。
可以按照下面的步骤进行调试
(1)删除所有的断点。
(2)按F5启动调试。
OSLab会首先弹出一个调试异常对话框。
(3)在调试异常对话框中选择“是”,调试会中断。
(4)在Consumer函数中等待Full信号量的代码行(第173行)WaitForSingleObject(FullSemaphoreHandle,INFINITE);
添加一个断点。
(5)在“断点”窗口(按Alt+F9打开)中此断点的名称上点击右键。
(6)在弹出的快捷菜单中选择“条件”。
(7)在“断点条件”对话框(按F1获得帮助)的表达式编辑框中,输入表达式“i==24”。
(8)点击“断点条件”对话框中的“确定”按钮。
(9)按F5继续调试。
只有当消费者线程尝试消费24号产品时才会在该条件断点处中断。
3.主要数据结构、实现代码及其说明
1).对PsWaitForSemaphore函数的修改:
PsWaitForSemaphore(
INPSEMAPHORESemaphore,
INULONGMilliseconds
)
/*++
功能描述:
信号量的Wait操作(P操作)。
参数:
Semaphore--Wait操作的信号量对象。
Milliseconds--等待超时上限,单位毫秒。
返回值:
STATUS_SUCCESS。
当你修改信号量使之支持超时唤醒功能后,如果等待超时,应该返回STATUS_TIMEOUT。
--*/
{
BOOLIntState;
STATUSa;
ASSERT(KeGetIntNesting()==0);
//中断环境下不能调用此函数。
IntState=KeEnableInterrupts(FALSE);
//开始原子操作,禁止中断。
//
//目前仅实现了标准记录型信号量,不支持超时唤醒功能,所以PspWait函数
//的第二个参数的值只能是INFINITE。
if(Semaphore->
Count>
0){
Semaphore->
Count--;
a=STATUS_SUCCESS;
}
elseif(Semaphore->
Count==0)
a=PspWait(&
Semaphore->
WaitListHead,Milliseconds);
KeEnableInterrupts(IntState);
//原子操作完成,恢复中断。
returna;
}
对PsReleaseSemaphore函数的修改:
PsReleaseSemaphore(
INLONGReleaseCount,
OUTPLONGPreviousCount
信号量的Signal操作(V操作)。
ReleaseCount--信号量计数增加的数量。
当前只能为1。
当你修改信号量使之支持
超时唤醒功能后,此参数的值能够大于等于1。
PreviousCount--返回信号量计数在增加之前的值。
如果成功释放信号量,返回STATUS_SUCCESS。
STATUSStatus;
//intbobo;
Count+ReleaseCount>
MaximumCount){
Status=STATUS_SEMAPHORE_LIMIT_EXCEEDED;
}else{
//
//记录当前的信号量的值。
if(NULL!
=PreviousCount){
*PreviousCount=Semaphore->
Count;
//目前仅实现了标准记录型信号量,每执行一次信号量的释放操作
//只能使信号量的值增加1。
if(ReleaseCount<
0)
return0;
for(;
ReleaseCount>
0&
&
!
(ListIsEmpty(&
WaitListHead));
ReleaseCount-=1){
PspWakeThread(&
WaitListHead,STATUS_SUCCESS);
}
Semaphore->
Count+=ReleaseCount;
Status=STATUS_SUCCESS;
KeEnableInterrupts(IntState);
returnStatus;
4.源程序并附上注释
#include"
psp.h"
VOID
PsInitializeSemaphore(
INLONGInitialCount,
INLONGMaximumCount
初始化信号量结构体。
Semaphore--要初始化的信号量结构体指针。
InitialCount--信号量的初始值,不能小于0且不能大于MaximumCount。
MaximumCount--信号量的最大值,必须大于0。
无。
ASSERT(InitialCount>
=0&
InitialCount<
=MaximumCount&
MaximumCount>
0);
Count=InitialCount;
MaximumCount=MaximumCount;
ListInitializeHead(&
WaitListHead);
STATUS
returna;
IntState=KeEnableInterrupts(FALSE);
if(Semaphore->
Status=STATUS_SEMAPHORE_LIMIT_EXCEEDED;
}else{
PspWakeThread(&
//////////////////////////////////////////////////////////////////////////
//
//下面是和信号量对象类型相关的代码。
//信号量对象类型指针。
POBJECT_TYPEPspSemaphoreType=NULL;
//用于初始化semaphore结构体的参数结构体。
typedefstruct_SEM_CREATE_PARAM{
LONGInitialCount;
LONGMaximumCount;
}SEM_CREATE_PARAM,*PSEM_CREATE_PARAM;
//semaphore对象的构造函数,在创建新semaphore对象时被调用。
PspOnCreateSemaphoreObject(
INPVOIDSemaphoreObject,
INULONG_PTRCreateParam
PsInitializeSemaphore((PSEMAPHORE)SemaphoreObject,
((PSEM_CREATE_PARAM)CreateParam)->
InitialCount,
MaximumCount);
//semaphore对象类型的初始化函数。
PspCreateSemaphoreObjectType(
VOID
OBJECT_TYPE_INITIALIZERInitializer;
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)){
KeBugCheck("
Failedtocreatesemaphoreobjecttype!
"
);
//semaphore对象的构造函数。
PsCreateSemaphoreObject(
INLONGMaximumCount,
INPSTRName,
OUTPHANDLESemaphoreHandle
PVOIDSemaphoreObject;
SEM_CREATE_PARAMCreateParam;
if(InitialCount<
0||MaximumCount<
=0||InitialCount>
MaximumCount){
returnSTATUS_INVALID_PARAMETER;
//创建信号量对象。
CreateParam.InitialCount=InitialCount;
CreateParam.MaximumCount=MaximumCount;
Status=ObCreateObject(PspSemaphoreType,
Name,
sizeof(SEMAPHORE),
(ULONG_PTR)&
CreateParam,
&
SemaphoreObject);
returnStatus;
Status=ObCreateHandle(SemaphoreObject,SemaphoreHandle);
ObDerefObject(SemaphoreObject);
//semaphore对象的signal操作函数。
PsReleaseSemaphoreObject(
INHANDLEHandle,
INPLONGPreviousCount
PSEMAPHORESemaphore;
if(ReleaseCount<
1){
//由semaphore句柄得到semaphore对象的指针。
Status=ObRefObjectByHandle(Handle,PspSemaphoreType,(PVOID*)&
Semaphore);
if(EOS_SUCCESS(Status)){
Status=PsReleaseSemaphore(Semaphore,ReleaseCount,PreviousCount);
ObDerefObject(Semaphore);
returnStatus;
5.程序运行时的初值和运行结果
a.使用EOS的信号量解决生产者-消费者问题
1).使用pc.c文件中的源代码,替换之前创建的EOS应用程序项目中EOSApp.c文件内的源代码
2).按F7生成修改后的EOS应用程序项目。
3).按F5启动调试。
4).在调试异常对话框中选择“否”,继续执行。
5).立即激活虚拟机窗口查看生产者-消费者同步执行的过程,如下图。
b.创建信号量
1).按F5启动调试EOS应用项目。
2).在调试异常对话框中选择“是”,调试会中断。
3).在main函数中创建Empty信号量的代码行(第77行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函数的定义(第19行),在此函数的第一行(第39行)代码处添加一个断点。
8).按F5继续调试,到断点处中断。
观察PsInitializeSemaphore函数中用来初始化信号量结构体成员的值,应该和传入CreateSemaphore函数的参数值是一致的。
9).按F10单步调试PsInitializeSemaphore函数执行的过程,查看信号量结构体被初始化的过程。
打开“调用堆栈”窗口,查看函数的调用层次。
c.等待、释放信号量
1).结束之前的调试。
2).删除所有的断点。
3).按F5重新启动调试。
4).在调试异常对话框中选择“是”,调试会中断。
5).在semaphore.c文件中的PsWaitForSemaphore函数的PspWait(&
WaitListHead,INFINITE);
代码行(第78行)添加一个断点。
6).按F5继续调试,并立即激活虚拟机窗口查看输出。
开始时生产者、消费者都不会被信号量阻塞,同步执行一段时间后才在断点处中断。
7).中断后,查看“调用堆栈”窗口,有Producer函数对应的堆栈帧,说明此次调用是从生产者线程函数进入的。
8).在“调用堆栈”窗口中双击Producer函数所在的堆栈帧,绿色箭头指向等待Empty信号量的代码行,查看Producer函数中变量i的值为14,表示生产者线程正在尝试生产14号产品。
9).在“调用堆栈”窗口中双击PsWaitForSemaphore函数的堆栈帧,查看Empty信号量计数(Semaphore->
Count)的值为-1,所以会调用PspWait函数将生产者线程放入Empty信号量的等待队列中进行等待(让出CPU)。
1
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统实验四 进程的同步 操作系统 实验 进程 同步
![提示](https://static.bdocx.com/images/bang_tan.gif)