操作系统实验四 进程的同步Word格式.docx

上传人:b****6 文档编号:20732846 上传时间:2023-01-25 格式:DOCX 页数:23 大小:476.96KB
下载 相关 举报
操作系统实验四 进程的同步Word格式.docx_第1页
第1页 / 共23页
操作系统实验四 进程的同步Word格式.docx_第2页
第2页 / 共23页
操作系统实验四 进程的同步Word格式.docx_第3页
第3页 / 共23页
操作系统实验四 进程的同步Word格式.docx_第4页
第4页 / 共23页
操作系统实验四 进程的同步Word格式.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

操作系统实验四 进程的同步Word格式.docx

《操作系统实验四 进程的同步Word格式.docx》由会员分享,可在线阅读,更多相关《操作系统实验四 进程的同步Word格式.docx(23页珍藏版)》请在冰豆网上搜索。

操作系统实验四 进程的同步Word格式.docx

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 经济市场

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

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