操作系统实验 进程的同步heu讲解.docx
- 文档编号:16970762
- 上传时间:2023-07-20
- 格式:DOCX
- 页数:25
- 大小:78.92KB
操作系统实验 进程的同步heu讲解.docx
《操作系统实验 进程的同步heu讲解.docx》由会员分享,可在线阅读,更多相关《操作系统实验 进程的同步heu讲解.docx(25页珍藏版)》请在冰点文库上搜索。
操作系统实验进程的同步heu讲解
操作系统
实验报告
课程名称
操作系统实验
课程编号
0906553
实验项目名称
进程的同步
学号
年级
姓名
专业
学生所在学院
指导教师
实验室名称地点
哈尔滨工程大学
计算机科学与技术学院.
进程的同步第六讲
一、实验概述实验名称1.
进程的同步实验目的2.
的信号量编程解决生产者EOS—消费者问题,理解进程同步的意义。
(1)使用
EOS的信号量的工作过程,理解进程同步的原理。
(2)调试跟踪,加深理解进程同步的原理。
EOS修改的信号量算法,使之支持等待超时唤醒功能(有限等待)(3)3.实验类型验证型实验,设计性实验4.实验内容)准备实验1(的信号量解决生产者-消费者问题
(2)使用EOS
信号量的工作过程3)调试EOS(6)等待信号量(阻塞))(不阻塞)3)等待信号量4释放信号量(不唤醒)5)等待释放信号量2)1创建信号量)
释放信号量(唤醒)EOS(4)修改的信号量算法二、实验环境OSLab操作系统集成实验环境三、实验过程1.设计思路和流程图
2.算法实现
3.需要解决的问题及解答
(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
原子操作前关中断
开始原子操作P操作
N
Wait操作的信号量大于0
Y
执行P操作
操作结束P
PsReleaseSemaphore
原子操作前关中断
开始原子操作V操作
NNNY
操作的信号量之P和V和大于缓冲队列长度
Y
记录当前信号量的值
信号量值P大于
返回“信号数目量超出范围”
释放信号量
+1
操作控制的信号量不0Y唤醒等待进程
被阻塞进程量小于要释放的信号量唤醒队列中进程
N
等待队列为空Y
返回“唤醒成功”
结束
4.主要数据结构、实现代码及其说明
1)修改PsWaitForSemaphore函数
if(Semaphore->Count>0){
Semaphore->Count--;
flag=STATUS_SUCCESS;
}//如果信号量大于零,说明尚有资源,可以为线程分配
else
flag=PspWait(&Semaphore->WaitListHead,Milliseconds);
KeEnableInterrupts(IntState);//原子操作完成,恢复中断。
returnflag;
}//否则,说明资源数量不够,不能再为线程分配资源,因此要使线程等待
2)修改PsReleaseSemaphore函数
if(Semaphore->Count+ReleaseCount>Semaphore->MaximumCount){
Status=STATUS_SEMAPHORE_LIMIT_EXCEEDED;
}else{
//
//记录当前的信号量的值。
//
if(NULL!
=PreviousCount){
*PreviousCount=Semaphore->Count;
}
intmm=Semaphore->Count;
//
目前仅实现了标准记录型信号量,每执行一次信号量的释放操作//
。
只能使信号量的值增加1//
//
while((!
ListIsEmpty(&Semaphore->WaitListHead))&&(ReleaseCount)){
PspWakeThread(&Semaphore->WaitListHead,STATUS_SUCCESS);
PspThreadSchedule();
ReleaseCount--;
}
Semaphore->Count=mm+ReleaseCount;
//
可能有线程被唤醒,执行线程调度。
//
//
Status=STATUS_SUCCESS;
}
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
当你修改信号量使之支持超时唤醒功能后,如果等待超时,应该返回STATUS_TIMEOUT。
--*/
{
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操作的信号量对象。
ReleaseCount--信号量计数增加的数量。
当前只能为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;
//
//目前仅实现了标准记录型信号量,每执行一次信号量的释放操作
//只能使信号量的值增加1。
//
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){
ALID_PARAMETER;
returnSTATUS_INV}
//
创建信号量对象。
//
//
CreateParam.InitialCount=InitialCount;
CreateParam.MaximumCount=MaximumCount;
Status=ObCreateObject(PspSemaphoreType,
Name,
sizeof(SEMAPHORE),
(ULONG_PTR)&CreateParam,
&SemaphoreObject);
if(!
EOS_SUCCESS(Status)){
returnStatus;
}
Status=ObCreateHandle(SemaphoreObject,SemaphoreHandle);
if(!
EOS_SUCCESS(Status)){
ObDerefObject(SemaphoreObject);
}
returnStatus;
}
//
signal操作函数。
//semaphore对象的//
STATUS
PsReleaseSemaphoreObject(
INHANDLEHandle,
INLONGReleaseCount,
INPLONGPreviousCount
)
{
STATUSStatus;
PSEMAPHORESemaphore;
if(ReleaseCount<1){
ALID_PARAMETER;returnSTATUS_INV
}
句柄得到//由semaphore对象的指针。
semaphore
Status=ObRefObjectByHandle(Handle,PspSemaphoreType,(PVOID*)&Semaphore);
if(EOS_SUCCESS(Status)){
Status=PsReleaseSemaphore(Semaphore,ReleaseCount,PreviousCount);
ObDerefObject(Semaphore);
}
returnStatus;
}
6.程序运行时的初值和运行结果
(1)准备实验
1)启动OSLab。
2)新建一个EOSKernel项目。
3)生成EOSKernel项目,从而在该项目文件夹中生成SDK文件夹。
4)新建一个EOS应用程序项目。
5)使用在第3步生成的SDK文件夹覆盖EOS应用程序项目文件夹中的SDK文件夹。
(2)使用EOS的信号量解决生产者-消费者问题
1)使用pc.c文件中的源代码,替换之前创建的EOS应用程序项目中EOSApp.c文件内的源代码。
2)按F7生成修改后的EOS应用程序项目。
3)按F5启动调试。
OSLab会首先弹出一个调试异常对话框。
4)在调试异常对话框中选择“否”,继续执行。
5)立即激活虚拟机窗口查看生产者-消费者同步执行的过程。
6)待应用程序执行完毕后,结束此次调试。
(3)调试EOS信号量的工作过程
1)创建信号量
1按F5启动调试EOS应用项目。
OSLab会首先弹出一个调试异常对话框。
○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函数执行的过程,查看信号量结构体被初始化的过程。
○打开“调用堆栈”窗口,查看函数的调用层次。
2)等待信号量(不阻塞)
1删除所有的断点(防止有些断点影响后面的调试)○。
2在eosapp.c文件的Producer函数中,等待Empty信号量的代码行(第144行)○WaitForSingleObject(EmptySemaphoreHandle,INFINITE);添加一个断点。
3按F5继续调试,到断点处中断。
○WaitForSingleObject函数最终会调用内核中的PsWaitForSemaphore函数完成等待操作。
所以,○4在semaphore.c文件中PsWaitForSemaphore函数的第一行(第68行)添加一个断点。
5按F5继续调试,到断点处中断。
○6按F10单步调试,直到完成PsWaitForSemaphore函数中的所有操作。
可以看到此次执行并没有○进行等待,只是将Empty信号量的计数减少了1(由10变为了9)就返回了。
3)释放信号量(不唤醒)
1删除所有的断点(防止有些断点影响后面的调试)○。
2在eosapp.c文件的Producer函数中,释放Full信号量的代码行(第152行)○ReleaseSemaphore(FullSemaphoreHandle,1,NULL);添加一个断点。
3按F5继续调试,到断点处中断。
○4按F11调试进入ReleaseSemaphore函数。
○5继续按F11调试进入PsReleaseSemaphoreObject函数。
○6先使用F10单步调试,当黄色箭头指向第269行时使用F11单步调试,进入○PsReleaseSemaphore函数。
7按F10单步调试,直到完成PsReleaseSemaphore函数中的所有操作。
可以看到此次执行没○有唤醒其它线程(因为此时没有线程在Full信号量上被阻塞),只是将Full信号量的计数增加了1(由0变为了1)。
4)等待信号量(阻塞)
1结束之前的调试。
○
2删除所有的断点。
○
3按F5重新启动调试。
OSLab会首先弹出一个调试异常对话框。
○4在调试异常对话框中选择“是”○,调试会中断。
5在semaphore.c文件中的PsWaitForSemaphore函数的○PspWait(&Semaphore->WaitListHead,INFINITE);代码行(第78行)添加一个断点。
6按F5继续调试,并立即激活虚拟机窗口查看输出。
开始时生产者、消费者都不会被信号量阻○塞,同步执行一段时间后才在断点处中断。
7中断后,查看“调用堆栈”窗口,有Producer函数对应的堆栈帧,说明此次调用是从生产者○线程函数进入的。
8在“调用堆栈”窗口中双击Producer函数所在的堆栈帧,绿色箭头指向等待Empty信号量○的代码行,查看Producer函数中变量i的值为14,表示生产者线程正在尝试生产14号产品。
在“调用堆栈”窗口中双击PsWaitForS
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统实验 进程的同步heu讲解 操作系统 实验 进程 同步 heu 讲解