操作系统试验进程同步.docx
- 文档编号:11695348
- 上传时间:2023-03-30
- 格式:DOCX
- 页数:19
- 大小:186.17KB
操作系统试验进程同步.docx
《操作系统试验进程同步.docx》由会员分享,可在线阅读,更多相关《操作系统试验进程同步.docx(19页珍藏版)》请在冰豆网上搜索。
操作系统试验进程同步
操作系统
实验报告
课程名称
操作系统实验
课程编号
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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统 试验 进程 同步