进程同步模拟设计.docx

上传人:b****0 文档编号:17031570 上传时间:2023-07-21 格式:DOCX 页数:17 大小:127.21KB
下载 相关 举报
进程同步模拟设计.docx_第1页
第1页 / 共17页
进程同步模拟设计.docx_第2页
第2页 / 共17页
进程同步模拟设计.docx_第3页
第3页 / 共17页
进程同步模拟设计.docx_第4页
第4页 / 共17页
进程同步模拟设计.docx_第5页
第5页 / 共17页
进程同步模拟设计.docx_第6页
第6页 / 共17页
进程同步模拟设计.docx_第7页
第7页 / 共17页
进程同步模拟设计.docx_第8页
第8页 / 共17页
进程同步模拟设计.docx_第9页
第9页 / 共17页
进程同步模拟设计.docx_第10页
第10页 / 共17页
进程同步模拟设计.docx_第11页
第11页 / 共17页
进程同步模拟设计.docx_第12页
第12页 / 共17页
进程同步模拟设计.docx_第13页
第13页 / 共17页
进程同步模拟设计.docx_第14页
第14页 / 共17页
进程同步模拟设计.docx_第15页
第15页 / 共17页
进程同步模拟设计.docx_第16页
第16页 / 共17页
进程同步模拟设计.docx_第17页
第17页 / 共17页
亲,该文档总共17页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

进程同步模拟设计.docx

《进程同步模拟设计.docx》由会员分享,可在线阅读,更多相关《进程同步模拟设计.docx(17页珍藏版)》请在冰点文库上搜索。

进程同步模拟设计.docx

进程同步模拟设计

进程同步模拟设计

——吃水果问题

1、课程设计目的与功能

1.1、目的

为下面吃水果的问题创建进程并利用通信API实现进程之间的同步模型。

能够处理以下的情形:

桌子上有一只盘子,最多可容纳两个水果,每次只能放入或者取出一个水果。

爸爸专门向盘子中放苹果,妈妈专门向盘子中放橘子,两个儿子专门等待吃盘子中的橘子,两个女儿专门等吃盘子中的苹果。

1.2、实现的功能

本程序共创建了6个在Windows系统环境下实现的线程,即Father、Mother、Son1、Son2、Daughter1和Daughter2等6个线程,以及Put_Apple、Put_Orange、Get_Apple1、Get_Apple2、Get_Orange1和Get_Orange2等6个函数,其中4个线程是用于实现爸爸、妈妈、儿子和女儿分别放水果和取水果的线程操作的,并分别调用这4个函数,来实现真正的操作。

在本程序中还设置了mutex互斥信号,empty、apple和orange等信号量,用于各线程之间获取资源和放弃资源等的线程之间的操作控制,并且设置了盘子容量上限量content。

其主要功能是用于实现爸爸和妈妈这2个互斥线程对于资源的使用操作以及爸爸和女儿、妈妈和儿子这2组同步线程对于资源的操作。

2、需求分析

当计算机中两个或者多个进程在执行时需要使用公用缓冲区,并且对该缓冲区采取了互斥措施,这时如果并发执行这些进程的时候就会造成CPU时间的极大浪费,这是操作系统设计要求不允许的。

而这种现象在操作系统和用户进程中大量存在。

因此为了解决这一问题,提出了同步的概念,即把异部环境下的一组并发进程,因直接制约而互相发送消息而进行互相合作、互相等待,使得各进程按一定的速度执行的过程称为进程间的同步。

在本系统中,爸爸与妈妈、儿子与女儿的线程操作是互斥的,但是爸爸与女儿、妈妈与儿子线程之间的操作是同步的。

因此要利用进程同步的方法来实现这几者之间的操作,当然其中也包含着互斥进程,因为盘子每次只能放入或者取出一个水果。

因为是在Windows操作系统下实现的,所以采用线程的方法来实现。

3、整体功能及设计

3.1数据结构的设计

在此次程序中一共涉及到线程、函数、互斥信号、信号量和常变量。

3.1.1线程

线程是指进程内的一个执行单元,也是进程内的可调度实体。

单个进程在任何给定时刻,可能有不止一个线程在运行。

但进程启动的同时启动了一个线程,该线程被称作主线程或执行线程。

一个进程除启动主线程外还可以启动多个线程,每个线程都共享进程的地址空间,并且共享着进程的地址空间及各种资源。

线程可以继续创建子线程。

如果主线程退出,主线程下的所有子线程将失败。

线程的创建格式如下:

其中括号中则需要列出该函数的各形参或者实参。

该函数的返回值为线程的句柄。

HANDLECreateThread();

CreateThread函数参数说明

参数

描述

lpThreadAttibutes

决定返回的句柄是否可以被子进程继承

dwStackSize

指定线程堆栈的初始大小

lpStratAddress

指定线程函数的起始地址

lpParameter

指定传递给线程函数的参数

dwCreationFlags

指定创建线程后是否立即启动

lpThreadId

取得内核给新生成的线程分配的线程ID号

在本程序中使用了Father、Mother、Son和Daughter等共4个线程。

等待函数:

阻塞线程的执行,直到满足指定的条件才返回。

WaitForSingleObject():

指定对象处于受信(singled)状态或超时返回。

原型如下:

DWORDWINAPIWaitForSingleObject(//单对象等待函数

__inHANDLEhHandle,//指定对象的句柄,通常可以使用线程句柄,当线程结束时,线程句柄变成受信状态

__inDWORDdwMilliseconds//超时时间,若为INFINITE,则不设置。

);

Father、Mother线程的作用是模拟实现向盘子中放苹果或者橘子的操作,当主程序执行之后创建了Father或者Mother线程,则该线程会独自占用整个资源,并执行Put_Apple或者Put_Orange函数来实现操作,在执行Father或者Mother线程时,首先会将信号量empty减1,来说明盘子中已经放置了一个水果,之后将互斥信号mutex置0,来说明盘子已经被占用,其他进程无法占用。

当实现了Put_Apple或者Put_Orange后,该线程会置mutex为1,来释放资源,表明该资源可以被其他线程所使用。

接下来将apple或者orange信号进行相应的设置,表明在盘子中已经放置了苹果或者橘子,Daughter或者Son线程可以从盘子中取苹果或者橘子了。

Daughter、Son线程的作用是模拟实现从盘子中取出苹果或者橘子的操作,当主程序中执行过Father或者Mother线程之后会释放资源,这时候Daughter或者Son线程便得到了资源,在得到资源即盘子后会首先将apple或者orange信号量进行设置,恢复原来的数值以表明盘子中的水果情况,并且将mutex互斥信号进行设置,表示资源正在被占用。

在实现了Get_Apple或者Get_Orange后,便对mutex互斥信号进行设置,以释放资源。

3.1.2函数

若干个函数组成一个程序文件,若干个程序文件组成一个完整的程序,因此函数是程序的基本组成部分。

在本程序中共创建了Put_Apple()、Put_Orange()、Get_Apple()和Get_Orange()等4个功能函数,分别用来模拟实现放苹果、放橘子、取苹果和取橘子的操作。

主函数main()主要作用就是为Father、Mother、Son和Daughter这四个线程服务,创建这几个线程,并在这些线程执行完毕后销毁它们。

主函数中Sleep()函数,控制主线程休眠一段时间,并在此期间执行其他其他子线程,在休眠时间过后主线程执行完,整个程序执行完毕。

3.1.3互斥信号和信号量

线程同步的方法有很多,最常用的有互斥(CMutex)、临界(CriticalSection)、信号量(Semaphore)和事件(Event)。

但本程序只用到了互斥和信号量。

其中mutex是各线程之间的互斥信号,当一个线程占用了资源之后,其他线程在没接收到通知的时候即互斥信号为0时便无法使用资源。

empty、apple和orange为3个信号量,分别来表示资源的使用状态,各线程根据这3个信号量来了解资源状态和使用资源。

这3个信号量的变化范围为0~content,content为盘子的容量,也是资源的容量。

CreatMutex()函数可以创建或打开一个互斥体对象,原型如下:

HANDLWINAPICreatMutex(

_inLPSECURITY_ATTRIBUTESlpMutexAttributes,//互斥体对象的安全属性,如果为NULL,则互斥体对象不能被子进程继承

_inBOOLbInitialOwner,//初始化互斥对象的所有者

_inLPCTSTRlpName//指定互斥对象的名字

);

CreateSemaphore()创建一个新的信号量

HANDLECreateSemaphore(

LPSECURITY_ATTRIBUTESlpSemaphoreAttributes,//信号量的安全特性

LONGlInitialCount,//设置信号量的初始计数

LONGlMaximumCount,//设置信号量的最大计数

LPCTSTRlpName//指定信号量对象的名称

);

ReleaseMutex():

释放互斥对象

BOOLWIANPIReleaseMutex(

HANDLEhMutex

);

ReleaseSemaphore()对指定的信号量增加指定的值;

BOOLReleaseSemaphore(

HANDLEhSemaphore,

LONGlReleaseCount,//这个信号量对象在当前基础上所要增加的值,这个值必须大于0,如果信号量加上这个值会导致信号量的当前值大于信号量创建时指定的最大值,那么这个信号量的当前值不变,同时这个函数返回FALSE

LPLONGlpPreviousCount//指向返回信号量上次值的变量的指针,如果不需要信号量上次的值,那么这个参数可以设置为NULL

);

3.2程序实现框图

3.2.1main函数

 

3.2.2Father、Mother线程

3.2.3Son1、Son2、Daughter1、Daughter2线程

4、编程实现

4.1各线程的声明:

DWORDWINAPIFather(LPVOIDlpParameter);//Father线程

DWORDWINAPIMother(LPVOIDlpParameter);//Mother线程

DWORDWINAPISon1(LPVOIDlpParameter);//Son1线程

DWORDWINAPISon2(LPVOIDlpParameter);//Son1线程

DWORDWINAPIDaughter1(LPVOIDlpParameter);//Daughter1线程

DWORDWINAPIDaughter2(LPVOIDlpParameter);//Daughter2线程

4.2各信号量、互斥信号和常变量

HANDLEmutex;//互斥信号mutex

HANDLEempty;//信号量empty

HANDLEapple;//信号量apple

HANDLEorange;//信号量orange

constintcontent=2;//常变量mutex

4.34个函数的声明

voidPut_Apple();

voidPut_Orange();

voidGet_Apple1();

voidGet_Apple2();

voidGet_Orange1();

voidGet_Orange2();

 

4.4主函数的程序代码

voidmain()

{

mutex=CreateMutex(NULL,FALSE,NULL);//创建mutex

empty=CreateSemaphore(NULL,content,content,NULL);//创建empty

apple=CreateSemaphore(NULL,0,content,NULL);//创建apple

orange=CreateSemaphore(NULL,0,content,NULL);//创建oarnge

HANDLEhThread1;

HANDLEhThread2;

HANDLEhThread3;

HANDLEhThread4;

HANDLEhThread5;

HANDLEhThread6;

hThread1=CreateThread(NULL,0,Father,NULL,0,NULL);//创建Father线程

hThread2=CreateThread(NULL,0,Mother,NULL,0,NULL);//创建Mother线程

hThread3=CreateThread(NULL,0,Son1,NULL,0,NULL);//创建Son1线程

hThread4=CreateThread(NULL,0,Son2,NULL,0,NULL);//创建Son2线程

hThread5=CreateThread(NULL,0,Daughter1,NULL,0,NULL);//创建Daughter1线程

hThread6=CreateThread(NULL,0,Daughter2,NULL,0,NULL);//创建Daughter2线程

CloseHandle(hThread1);//销毁Father线程

CloseHandle(hThread2);//销毁Mother线程

CloseHandle(hThread3);//销毁Son线程

CloseHandle(hThread4);//销毁Daughter线程

Sleep(30000);//主程序将在30秒后结束

}

4.5各线程的程序代码

DWORDWINAPIFather(LPVOIDlpParameter)//Father线程实现

{

while

(1)

{

WaitForSingleObject(empty,INFINITE);

WaitForSingleObject(mutex,INFINITE);

Put_Apple();

Sleep(1500);

ReleaseMutex(mutex);

ReleaseSemaphore(apple,1,NULL);

}

}

DWORDWINAPIMother(LPVOIDlpParameter)//Mother线程实现

{

while

(1)

{

WaitForSingleObject(empty,INFINITE);

WaitForSingleObject(mutex,INFINITE);

Put_Orange();

Sleep(1500);

ReleaseMutex(mutex);

ReleaseSemaphore(orange,1,NULL);

}

}

DWORDWINAPISon1(LPVOIDlpParameter)//Son1线程实现

{

while

(1)

{

WaitForSingleObject(orange,INFINITE);

WaitForSingleObject(mutex,INFINITE);

Get_Orange1();

Sleep(1500);

ReleaseMutex(mutex);

ReleaseSemaphore(empty,1,NULL);

}

}

DWORDWINAPISon2(LPVOIDlpParameter)//Son2线程实现

{

while

(1)

{

WaitForSingleObject(orange,INFINITE);

WaitForSingleObject(mutex,INFINITE);

Get_Orange2();

Sleep(1500);

ReleaseMutex(mutex);

ReleaseSemaphore(empty,1,NULL);

}

}

DWORDWINAPIDaughter1(LPVOIDlpParameter)//Daughter1线程实现

{

while

(1)

{

WaitForSingleObject(apple,INFINITE);

WaitForSingleObject(mutex,INFINITE);

Get_Apple1();

Sleep(1500);

ReleaseMutex(mutex);

ReleaseSemaphore(empty,1,NULL);

}

}

DWORDWINAPIDaughter2(LPVOIDlpParameter)//Daughter2线程实现

{

while

(1)

{

WaitForSingleObject(apple,INFINITE);

WaitForSingleObject(mutex,INFINITE);

Get_Apple2();

Sleep(1500);

ReleaseMutex(mutex);

ReleaseSemaphore(empty,1,NULL);

}

}

4.6各函数的程序代码

voidPut_Apple()//Father放苹果

{

cout<<"爸爸要放苹果了!

"<

Sleep(1500);

cout<<"苹果已经被放进去了!

"<

}

voidPut_Orange()//Mother放橘子

{

cout<<"妈妈要放橘子了!

"<

Sleep(1500);

cout<<"橘子已经被放进去了!

"<

}

voidGet_Apple1()//Daughter1取苹果

{

cout<<"女儿A要吃苹果了!

"<

Sleep(1500);

cout<<"苹果已经被拿出来了!

"<

}

voidGet_Apple2()//Daughter2取苹果

{

cout<<"女儿B要吃苹果了!

"<

Sleep(1500);

cout<<"苹果已经被拿出来了!

"<

}

voidGet_Orange1()//Son1取橘子

{

cout<<"儿子A要吃橘子了!

"<

Sleep(1500);

cout<<"橘子已经被拿出来了!

"<

}

voidGet_Orange2()//Son2取橘子

{

cout<<"儿子B要吃橘子了!

"<

Sleep(1500);

cout<<"橘子已经被拿出来了!

"<

}

5、运行结果与运行情况分析

程序的运行结果如下:

由于是设定了Sleep()函数,所以程序在执行了30000毫秒,即30秒之后便自动结束。

程序开始时,在main()函数中创建各个线程,在创建之后,便开始按照同步进程的执行规律进行执行,在每个线程中都设置有Sleep()函数,用来进行最终结果输出的界面控制,即每隔1.5秒便输出一个线程执行的结果,这样依次进行。

由于线程的调度没有明显的显示结果,所以在4个函数中专门设置了输出语句以显式的方式来表现各线程执行的结果。

由于在时间上进行了设置,所以最后输出了3组线程执行的结果,即从爸爸或者妈妈放第一个水果,一直到儿子或者女儿将盘子中的最后一个水果取走。

 

6、自我评价与总结

6.1比较满意之处

在设计这个题目之前,由于对于进程同步的实现方法不是很了解,对于怎样具体实现进程同步有很大的疑问,所以在网上进行了查找,希望找到相关的资料,但几经搜索都没有找到比较适合的材料。

网上的资料主要以PV原语的实现为主,而本实验是以实现进程同步系统的功能为主,因此对于实现功能有一定的帮助,但对于P原语语句与V原语语句的具体实现并没有给出。

就是在这种虽然有一定基础,但并不能完全依靠的情况下,自己通过查找相关的书籍,了解本系统中可能涉及到的数据结构知识后,成功的实现了进程同步模型系统的功能。

自己对于从对进程同步只是有一个概念上的认识,到最终将它的功能实现这一过程感到满意与欣慰,因为这些都是通过自己的努力一步一步实现的。

在程序设计方面,本程序的数据结构简单,主要包括线程、函数和进程同步中的各种互斥信号和信号量。

程序的数据结构精简,程序设计简介,一目了然。

麻雀虽小,但五脏俱全,凡是实现能够实现该设计功能的组成部分全部包括。

6.2不足之处

首先,虽然熟悉和了解了程序中各数据结构的定义和创建,但是在一些细节问题上还是没有一个很明确的认识,例如虽然知道HANDLE句柄,在程序中可以用于创建线程,但对于其实现的原理还不是很清楚,现在只是机械的合法的使用它。

其次对于Sleep()函数的理解也不够深刻,在本程序中使用次函数的目的主要是为了进行结果输出时可以将结果以此逐渐的输出,而不是使结果一次性的输出出来,对其在各线程之间是怎样进行操作的并不是很清楚。

最后在运行界面的设计上有些过于简单,输出的信息并不是很详细,与网上一些比较成熟的进程同步的其他模型实现的运行界面相比是比较简陋的,各线程在使用过资源后,资源内部的情况,各信号量的变化并没有很具体的显示出来,当然在以后的设计中会更加的完善。

6.3本次课程设计的收获

本程序是用来实现进程同步模型系统,其核心部分就是如何利用PV原语的原理以及C++的编程语言将线程的同步与互斥操作实现。

所以实现这一功能只需要将线程这一概念理解清楚并熟练运用即可,并不需要其他非常复杂的数据结构和编译环境。

对于我而言重点则在于对线程这一数据结构的理解。

刚开始设计该程序的时候,虽然拥有了了线程的同步与互斥的理论基础和PV原语的实现原理,但对于这些知识的具体实现还是没有头绪,在查阅了很多关于生产者消费者的一些源程序后,看到了关于线程等的一些数据结构的定义、创建和使用方法,但还是由于没有像书上那样进行讲解所以并没有看懂,所以在找不到相关源程序后,我查阅了与VC++相关的书籍,在仔细学习了线程这一数据结构之后,便对于那些经典的生产者消费者问题有进一步的了解。

这个程序的编写是在《VC++深入详解》这本书中关于简单多线程程序的一个例子的基础上改编过来的,这个例子只是实现了几个简单多线程的互斥操作,所以我利用PV原语的原理在互斥的基础上添加了同步操作的成分。

当然也只是将最基本的同步操作实现语句添加了进去。

不过在调试编译之后便成功运行了。

6.4其他方法

进程同步的实现可以使用2种方法,一是在Windows系统环境下使用线程来实现,二是在Linux系统环境下使用进程来实现。

由于自己习惯使用Windows操作系统,所以使用的是第一种方法。

7、参考文献

(1)张尧学、史美林、张高《计算机操作系统教程》(第三版)清华大学出版社.2006年10月第3版

(2)李晓黎《Windows系统编程》人民邮电出版社2012年1月第1版

(3)孙鑫、余安萍《VC++深入详解》电子工业出版社2008年4月第1

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

当前位置:首页 > PPT模板 > 简洁抽象

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2