操作系统试验进程同步.docx

上传人:b****4 文档编号:11695348 上传时间:2023-03-30 格式:DOCX 页数:19 大小:186.17KB
下载 相关 举报
操作系统试验进程同步.docx_第1页
第1页 / 共19页
操作系统试验进程同步.docx_第2页
第2页 / 共19页
操作系统试验进程同步.docx_第3页
第3页 / 共19页
操作系统试验进程同步.docx_第4页
第4页 / 共19页
操作系统试验进程同步.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

操作系统试验进程同步.docx

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

操作系统试验进程同步.docx

操作系统试验进程同步

操作系统

实验报告

课程名称

操作系统实验

课程编号

0906553

实验项目名称

进程的同步

学号

年级

姓名

专业

学生所在学院

指导教师

实验室名称地点

哈尔滨工程大学

计算机科学与技术学院.

第四讲进程的同步

一、实验概述

1.实验名称

进程的同步

2.实验目的

使用EOS的信号量,编程解决生产者—消费者问题,理解进程同步的意义。

调试跟踪EOS信号量的工作过程,理解进程同步的原理。

修改EOS的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。

3.实验类型

验证+设计4.实验内容

(1)准备实验

(2)使用EOS的信号量解决生产者-消费者问题

(3)调试EOS信号量的工作过程

的信号量算法)修改EOS(4二、实验环境

EOS操作系统和OSLab集成实验环境,主要运用了C语言。

三、实验过程

3.需要解决的问题及解答

(1)P143,生产者在生产了13号产品后本来要继续生产14号产品,可此时生产者为什么必须等待消费者消费了4号产品后,才能生产14号产品呢?

生产者和消费者是怎样使用同步对象来实现该同步过程的呢?

这是因为临界资源的限制。

临界资源就像产品仓库,只有“产品仓库”空闲生产者才能生产东西,有权向里面放东西。

因此它必须要等到消费者,取走产品,临界资源空闲时,才能继续生产14号产品。

(2)P147-四思考与练习-2.绘制ps/semaphore.c文件内PsWaitForSemaphore和函数的流程图。

PsReleaseSemaphore

函数开始

Semaphore->Count+ReleaseCount>Semmaphore->MaxinCount队

函数开始返回SEMAPHORLINITEXCEECED

开始原子操作开始原子操作信号量减一信小于线程进

号量0?

记录当前信号量

Status=STAUS

信号量加1Semaphore->Count<=0?

从阻塞列唤醒

入阻塞

函数结束

原子操作完成

函数结束

返回Status=STA

TUSSUCESS

5.源程序并附上注释

#includepsp.h

VOID

PsInitializeSemaphore(

INPSEMAPHORESemaphore,

INLONGInitialCount,

INLONGMaximumCount

/*++

功能描述:

初始化信号量结构体。

参数:

Semaphore--要初始化的信号量结构体指针。

InitialCount--信号量的初始值,不能小于0且不能大于MaximumCount。

MaximumCount--信号量的最大值,必须大于0。

返回值:

无。

{ASSERT(InitialCount>=0&&InitialCount<=MaximumCount&&MaximumCount>0);

Semaphore->Count=InitialCount;

Semaphore->MaximumCount=MaximumCount;

ListInitializeHead(&Semaphore->WaitListHead);}

STATUS

PsWaitForSemaphore(INPSEMAPHORESemaphore,ININTMilliseconds,INSTATUSi)

/*++

功能描述:

信号量的Wait操作(P操作)。

参数:

Semaphore--Wait操作的信号量对象。

Milliseconds--等待超时上限,单位毫秒。

返回值:

STATUS_SUCCESS。

--*/

{BOOLIntState;

ASSERT(KeGetIntNesting()==0);//中断环境下不能调用此函数。

IntState=KeEnableInterrupts(FALSE);//开始原子操作,禁止中断。

//目前仅实现了标准记录型信号量,不支持超时唤醒功能,所以PspWait函数的第二个参数的值只能是INFINITE。

if(Semaphore->Count>0)

{Semaphore->Count--;

i=STATUS_SUCCESS;}

else{i=PspWait(&Semaphore->WaitListHead,Milliseconds);}

KeEnableInterrupts(IntState);//原子操作完成,恢复中断。

returni;

}

STATUS

PsReleaseSemaphore(INPSEMAPHORESemaphore,INLONGReleaseCount,OUTPLONGPreviousCount)

/*++

功能描述:

信号量的Signal操作(V操作)。

参数:

Semaphore--Wait操作的信号量对象。

--信号量计数增加的数量。

当前只能为1。

当你修改信号量使之支持超时唤醒功能后,此参数的值能够大于等于1。

PreviousCount--返回信号量计数在增加之前的值。

返回值:

如果成功释放信号量,返回STATUS_SUCCESS。

--*/

{STATUSStatus;

BOOLIntState;

IntState=KeEnableInterrupts(FALSE);//开始原子操作,禁止中断。

if(Semaphore->Count+ReleaseCount>Semaphore->MaximumCount){

Status=STATUS_SEMAPHORE_LIMIT_EXCEEDED;

}else{

if(NULL!

=PreviousCount){

*PreviousCount=Semaphore->Count;}

INTj=Semaphore->Count;

while((!

ListIsEmpty(&Semaphore->WaitListHead))&&(ReleaseCount)){

PspWakeThread(&Semaphore->WaitListHead,STATUS_SUCCESS);

PspThreadSchedule();

ReleaseCount--;

}

Semaphore->Count=j+ReleaseCount;

Status=STATUS_SUCCESS;

}

KeEnableInterrupts(IntState);//原子操作完成,恢复中断。

returnStatus;

}

POBJECT_TYPEPspSemaphoreType=NULL;//用于初始化semaphore结构体的参数结构体。

typedefstruct_SEM_CREATE_PARAM{

LONGInitialCount;

LONGMaximumCount;

}SEM_CREATE_PARAM,*PSEM_CREATE_PARAM;

//semaphore对象的构造函数,在创建新semaphore对象时被调用。

VOID

PspOnCreateSemaphoreObject(

INPVOIDSemaphoreObject,

INULONG_PTRCreateParam

{PsInitializeSemaphore((PSEMAPHORE)SemaphoreObject,

((PSEM_CREATE_PARAM)CreateParam)->InitialCount,

((PSEM_CREATE_PARAM)CreateParam)->MaximumCount);

}

//

//semaphore对象类型的初始化函数。

//

VOID

PspCreateSemaphoreObjectType(VOID)

{STATUSStatus;

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对象的构造函数。

//

STATUS

PsCreateSemaphoreObject(

INLONGInitialCount,

INLONGMaximumCount,

INPSTRName,

OUTPHANDLESemaphoreHandle

{STATUSStatus;

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;

if(!

EOS_SUCCESS(Status)){

Status=ObCreateHandle(SemaphoreObject,SemaphoreHandle);

if(!

EOS_SUCCESS(Status)){ObDerefObject(SemaphoreObject);}

returnStatus;

}

//

//semaphore对象的signal操作函数。

//

STATUS

PsReleaseSemaphoreObject(INHANDLEHandle,INLONGReleaseCount,INPLONGPreviousCount)

{STATUSStatus;

PSEMAPHORESemaphore;

if(ReleaseCount<1){returnSTATUS_INVALID_PARAMETER;}

//由semaphore句柄得到semaphore对象的指针。

Status=ObRefObjectByHandle(Handle,PspSemaphoreType,(PVOID*)&Semaphore);

if(EOS_SUCCESS(Status)){

Status=PsReleaseSemaphore(Semaphore,ReleaseCount,PreviousCount);

ObDerefObject(Semaphore);

}

returnStatus;

}

#includeEOSApp.h

缓冲池。

//

10

#defineBUFFER_SIZE

intBuffer[BUFFER_SIZE];

//产品数量。

#definePRODUCT_COUNT30

//用于生产者和消费者同步的对象句柄。

HANDLEMutexHandle;

HANDLEEmptySemaphoreHandle;

HANDLEFullSemaphoreHandle;

//生产者和消费者的线程函数

ULONGProducer(PVOIDParam);

ULONGConsumer(PVOIDParam);

//main函数参数的意义:

//argc-argv数组的长度,大小至少为1,argc-1为命令行参数的数量。

//argv-字符串指针数组,数组长度为命令行参数个数+1。

其中argv[0]固定指向当前进程所执行的可执行文件的路径

//符串,argv[1]及其后面的指针指向各个命令行参数。

intmain(intargc,char*argv[])

{HANDLEProducerHandle;

HANDLEConsumerHandle;

#ifdef_DEBUG

__asm(int$3\nnop);

#endif

//创建用于互斥访问缓冲池的Mutex对象。

MutexHandle=CreateMutex(FALSE,NULL);

if(NULL==MutexHandle){return1;}

//创建Empty信号量,表示缓冲池中空缓冲区数量。

初始计数和最大计数都为BUFFER_SIZE。

EmptySemaphoreHandle=CreateSemaphore(BUFFER_SIZE,BUFFER_SIZE,NULL);

if(NULL==EmptySemaphoreHandle){return2;}

//创建Full信号量,表示缓冲池中满缓冲区数量。

初始计数为0,最大计数为BUFFER_SIZE。

FullSemaphoreHandle=CreateSemaphore(0,BUFFER_SIZE,NULL);

if(NULL==FullSemaphoreHandle){return3;}

//创建生产者线程。

ProducerHandle=CreateThread(0,//默认堆栈大小

Producer,//线程函数入口地址

NULL,//线程函数参数

//创建标志0,

//线程ID

NULL);

if(NULL==ProducerHandle){

return4;}

//创建消费者线程。

ConsumerHandle=CreateThread(0,Consumer,NULL,0,NULL);

if(NULL==ConsumerHandle){return5;}

//等待生产者线程和消费者线程结束。

WaitForSingleObject(ProducerHandle,INFINITE);

WaitForSingleObject(ConsumerHandle,INFINITE);

//关闭句柄

CloseHandle(MutexHandle);

CloseHandle(EmptySemaphoreHandle);

CloseHandle(FullSemaphoreHandle);

CloseHandle(ProducerHandle);

CloseHandle(ConsumerHandle);

return0;

}

//生产者线程函数。

ULONGProducer(PVOIDParam)

{inti;

intInIndex=0;

for(i=0;i

while(WAIT_TIMEOUT==WaitForSingleObject(EmptySemaphoreHandle,300)){

printf(Producerwaitforemptysemaphoretimeout\n);

}

WaitForSingleObject(MutexHandle,INFINITE);

printf(Producea%d\n,i);

Buffer[InIndex]=i;

InIndex=(InIndex+1)%BUFFER_SIZE;

ReleaseMutex(MutexHandle);

ReleaseSemaphore(FullSemaphoreHandle,1,NULL);

//休息一会。

每500毫秒生产一个数。

Sleep(500);}

return0;}

//消费者线程函数。

ULONGConsumer(PVOIDParam)

{inti;

intOutIndex=0;

for(i=0;i

while(WAIT_TIMEOUT==WaitForSingleObject(FullSemaphoreHandle,300)){

printf(Consumerwaitforfullsemaphoretimeout\n);

}

WaitForSingleObject(MutexHandle,INFINITE);

printf(\\t\tConsumea%d\n,Buffer[OutIndex]);

OutIndex=(OutIndex+1)%BUFFER_SIZE;

ReleaseMutex(MutexHandle);

ReleaseSemaphore(EmptySemaphoreHandle,1,NULL);

//休息一会儿。

让前10个数的消费速度比较慢,后面的较快。

}return0;}

if(i<10){Sleep(2000);}else{Sleep(100);}

6.程序运行时的初值和运行结果

3.1准备实验

1.启动OSLab。

2.新建一个EOSKernel项目。

3.生成EOSKernel项目,从而在该项目文件夹中生成SDK文件夹。

4.新建一个EOS应用程序项目。

5.使用在第3步生成的SDK文件夹覆盖EOS应用程序项目文件夹中的SDK文件夹。

3.2使用EOS的信号量解决生产者-消费者问题

1.使用pc.c文件中的源代码,替换之前创建的EOS应用程序项目中EOSApp.c文件内的源代码。

2.按F7生成修改后的EOS应用程序项目。

3.按F5启动调试。

OSLab会首先弹出一个调试异常对话框。

4.在调试异常对话框中选择“否”,继续执行。

5.立即激活虚拟机窗口查看生产者-消费者同步执行的过程。

6.待应用程序执行完毕后,结束此次调试。

3.3调试EOS信号量的工作过程

3.3.1创建信号量

会首先弹出一个调试异常对话框。

OSLab应用项目。

EOS启动调试F5按1.

2.在调试异常对话框中选择“是”,调试会中断。

3.在main函数中创建Empty信号量的代码行,第77行添加一个断点。

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函数执行的过程,查看信号量结构体被初始化的过程。

打开“调用堆栈”窗口,查看函数的调用层次。

3.3.2等待、释放信号量

3.3.2.1等待信号量(不阻塞)

1.删除所有的断点(防止有些断点影响后面的调试)。

2.在eosapp.c文件的Producer函数中,等待Empty信号量的代码行(第144行)添加一个断点。

3.按F5继续调试,到断点处中断。

4.WaitForSingleObject函数最终会调用内核中的PsWaitForSemaphore函数完成等待操作。

所以,在semaphore.c文件中PsWaitForSemaphore函数的第一行(第68行)添加一个断点。

5.按F5继续调试,到断点处中断。

6.按F10单步调试,直到完成PsWaitForSemaphore函数中的所有操作。

可以看到此次执行并没有进行等待,只是将Empty信号量的计数减少了1(由10变为了9)就返回了。

3.3.2.2释放信号量(不唤醒)

1.删除所有的断点(防止有些断点影响后面的调试)。

2.在eosapp.c文件的Producer函数中,释放Full信号量的代码行(第152行)添加一个断点。

3.按F5继续调试,到断点处中断。

4.按F11调试进入ReleaseSemaphore函数。

5.继续按F11调试进入PsReleaseSema

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

当前位置:首页 > 小学教育 > 其它课程

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

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