进程同步模型系统的设计—吃水果
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
课程设计
课程设计任务书
学生: Miss屠专业班级: 08计科
指导教师:王海英工作单位:计算机科学与技术学院
题目: 进程同步模型系统的设计——吃水果问题
初始条件:
1.预备容:阅读操作系统的进程管理章节容,对进程的同步和互斥,以及信号量机制度有深入的理解。
2.实践准备:掌握一种计算机高级语言的使用。
要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写
等具体要求)
1.为下面吃水果的问题创建进程并利用通信API实现进程之间的同步模型。
能够处理以下的情形:桌子上有一只盘子,最多可容纳两个水果,每次只能放入或者取出一个水果。
爸爸专门向盘子中放苹果,妈妈专门向盘子中放橘子,两个儿子专门等待吃盘子中的橘子,两个女儿专门等吃盘子中的苹果。
2.设计报告容应说明:
⑴课程设计目的与功能;
⑵需求分析,数据结构或模块说明(功能与框图);
⑶源程序的主要部分;
⑷运行结果与运行情况分析;
⑸自我评价与总结:
i)你认为你完成的设计哪些地方做得比较好或比较出色;
ii)什么地方做得不太好,以后如何改正;
iii)从本设计得到的收获(在编写,调试,执行过程中的经验和教训);
iv)完成本题是否有其他的其他方法(如果有,简要说明该方法);
时间安排:
设计安排一周:周1、周2:完成程序分析及设计。
周2、周3:完成程序调试及测试。
周4、周5:撰写课程设计报告。
指导教师签名:年月日
系主任(或责任教师)签名:年月日
进程同步模型系统的设计
——吃水果问题
1、课程设计目的与功能
1.1、目的
为下面吃水果的问题创建进程并利用通信API实现进程之间的同步模型。
能够处理以下的情形:桌子上有一只盘子,最多可容纳两个水果,每次只能放入或者取出一个水果。
爸爸专门向盘子中放苹果,妈妈专门向盘子中放橘子,两个儿子专门等待吃盘子中的橘子,两个女儿专门等吃盘子中的苹果。
1.2、实现的功能
本程序共创建了4个在windows系统环境下实现的线程,即Fahter、Mother、Son和Daughter等4个线程,以及putapple、putorange、getapple和getorange 等4个函数,其中4个线程是用于实现爸爸、妈妈、儿子和女儿分别放水果和取水果的线程操作的,并分别调用这4个函数,来实现真正的操作。
在本程序中还设置了mutex互斥信号、empty、apple和orange等信号量,用于各线程之间获取资源和放弃资源等的线程之间的操作控制,并且设置了盘子容量上线常量content。
其主要功能是用于实现爸爸和妈妈这2个互斥线程对于资源的使用操作以及爸爸和女儿、妈妈和儿子这2组同步线程对于资源的操作。
2、需求分析
当计算机中两个或者多个进程在执行时需要使用公用缓冲区,并且对该缓冲区采取了互斥措施,这时如果并发执行这些进程的时候就会造成CPU时间的极大
浪费,这是操作系统设计要求不允许的。
而这种现象在操作系统和用户进程量存在。
因此为了解决这一问题,提出了同步的概念,即把异部环境下的一组并发进程,因直接制约而互相发送消息而进行互相合作、互相等待,使得各进程按一定的速度执行的过程称为进程间的同步。
在本系统中,爸爸与妈妈、儿子与女儿的线程操作是互斥的,但是爸爸与女儿、妈妈与儿子线程之间的操作是同步的。
因此要利用进程同步的方法来实现这几者之间的操作,当然其中也包含着互斥进程,因为盘子每次只能放入或者取出一个水果。
因为是在windows操作系统下实现的,所以是采用线程的方法实现的。
3、整体功能及设计
3.1数据结构的设计
在此次程序中一共涉及到线程、函数、互斥信号、信号量和常变量。
3.1.1线程
线程是指进程的一个执行单元,也是进程的可调度实体。
单个进程在任何给定时刻,可能有不止一个线程在运行。
但进程启动的同时启动了一个线程,该线程被称作主线程或执行线程。
一个进程除启动主线程外还可以启动多个线程,每个线程都共享进程的地址空间,并且共享着进程的地址空间及各种资源。
线程可以继续创建子线程。
如果主线程退出,主线程下的所有子线程将失败。
线程的创建格式如下:其中括号中则需要列出该函数的各形参或者实参。
该函数的返回值为线程的句柄。
HANDLE CreateThread( );
CreateThread函数参数说明
在本程序中使用了Father、Mother、Son和Daughter等共4个线程。
Father、Mother线程的作用是模拟实现向盘子中放苹果或者橘子的操作,当主程序执行之后创建了Father或者Mother线程,则该线程会独自占用整个资源,并执行putapple或者putorange函数来实现操作,在执行Father或者Mother 线程时,首先会将信号量empty减1,来说明盘子中已经放置了一个水果,之后将互斥信号mutex置0,来说明盘子已经被占用,其他进程无法占用。
当实现了putapple或者putorange后,该线程会置mutex为1,来释放资源,表明该资源可以被其他线程所使用。
接下来将apple或者orange信号进行相应的设置,表明在盘子中已经放置了苹果或者橘子,Daughter或者Son线程可以从盘子中取苹果或者橘子了。
Daughter 、Son线程的作用是模拟实现从盘子中取出苹果或者橘子的操作,当主程序中执行过Father或者Mother线程之后会释放资源,这时候Daughter 或者Son线程便得到了资源,在得到资源即盘子后会首先将apple或者orange 信号量进行设置,恢复原来的数值以表明盘子中的水果情况,并且将mutex互斥信号进行设置,表示资源正在被占用。
在实现了getapple或者getorange后,便对mutex互斥信号进行设置,以释放资源。
3.1.2函数
若干个函数组成一个程序文件,若干个程序文件组成一个完整的程序,因此函数是程序的基本组成部分。
在本程序中共创建了putapple( )、putorange( )、getapple( )和getorange( )等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为盘子的容量,也是资源的容量。
3.2程序实现框图
3.2.1 main函数
3.2.2 Father、Mother线程
3.2.3 Son、Daughter线程
4、编程实现
4.1各线程的声明:
DWORD WINAPI Father(LPVOID lpParameter);//Father线程DWORD WINAPI Mother(LPVOID lpParameter);//Mother线程DWORD WINAPI Son(LPVOID lpParameter);//Son线程
DWORD WINAPI Daughter(LPVOID lpParameter);//Daughter线程
4.2 各信号量、互斥信号和常变量
HANDLE mutex;//互斥信号mutex
HANDLE empty; //信号量empty
HANDLE apple; //信号量apple
HANDLE orange; //信号量orange
const int content=2; //常变量mutex
4.3个函数的声明
void putapple( );
void putorange( );
void getapple( );
void getorange( );
4.4主函数的程序代码
void main()
{
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
HANDLE hThread1;
HANDLE hThread2;
HANDLE hThread3;
HANDLE hThread4;
hThread1=CreateThread(NULL,0,Father,NULL,0,NULL);//创建Father线程hThread2=CreateThread(NULL,0,Mother,NULL,0,NULL);//创建Mother线程hThread3=CreateThread(NULL,0,Son,NULL,0,NULL);//创建Son线程
hThread4=CreateThread(NULL,0,Daughter,NULL,0,NULL);//创建Daughter 线程
CloseHandle(hThread1);//销毁Father线程
CloseHandle(hThread2);//销毁Mother线程
CloseHandle(hThread3);//销毁Son线程
CloseHandle(hThread4);//销毁Daughter线程
Sleep(35000);//主程序将在30秒后结束
}
4.5各线程的程序代码
DWORD WINAPI Father(LPVOID lpParameter)//Father线程实现
{
while(1)
{
WaitForSingleObject(empty,INFINITE);
WaitForSingleObject(mutex,INFINITE);
putapple( );
Sleep(1500);
ReleaseMutex(mutex);
ReleaseSemaphore(apple,1,NULL);
}
}
DWORD WINAPI Mother(LPVOID lpParameter)//Mother线程实现{
while(1)
{
WaitForSingleObject(empty,INFINITE);
WaitForSingleObject(mutex,INFINITE);
putorange( );
Sleep(1500);
ReleaseMutex(mutex);
ReleaseSemaphore(orange,1,NULL);
}
}
DWORD WINAPI Son(LPVOID lpParameter)//Son线程实现
{
while(1)
{
WaitForSingleObject(orange,INFINITE);
WaitForSingleObject(mutex,INFINITE);
getorange( );
Sleep(1500);
ReleaseMutex(mutex);
ReleaseSemaphore(empty,1,NULL);
}
}
DWORD WINAPI Daughter(LPVOID lpParameter)//Daughter线程实现{
while(1)
{
WaitForSingleObject(apple,INFINITE);
WaitForSingleObject(mutex,INFINITE);
getapple( );
Sleep(1500);
ReleaseMutex(mutex);
ReleaseSemaphore(empty,1,NULL);
}
}
4.6各函数的程序代码
void putapple( )//Father放苹果
{
cout<<"爸爸要放苹果了!"<<endl;
Sleep(1500);
cout<<"苹果已经被放进去了!"<<endl;
}
void putorange( )//Mother放橘子
{
cout<<"妈妈要放橘子了!"<<endl;
Sleep(1500);
cout<<"橘子已经被放进去了!"<<endl; }
void getapple( )//Daughter取苹果
{
cout<<"女儿要吃苹果了!"<<endl;
Sleep(1500);
cout<<"苹果已经被拿出来了!"<<endl; }
void getorange( )//Son取橘子
{
cout<<"儿子要吃橘子了!"<<endl;
Sleep(1500);
cout<<"橘子已经被拿出来了!"<<endl; }
5、运行结果与运行情况分析
程序的运行结果如下:
各线程执行完一次的结果:
由于是设定了Sleep( )函数,所以程序在执行了35000毫秒,即35秒之后便自动结束。
程序开始时,在main( )函数中创建各个线程,在创建之后,便开始按照同步进程的执行规律进行执行,在每个线程中都设置有Sleep( )函数,用来进行最终结果输出的界面控制,即每隔1.5秒便输出一个线程执行的结果,这样依次进行。
由于线程的调度没有明显的显示结果,所以在4个函数中专门设置了输出语句以显式的方式来表现各线程执行的结果。
由于在时间上进行了设
置,所以最后输出了3组线程执行的结果,即从爸爸或者妈妈放第一个水果,一直到儿子或者女儿将盘子中的最后一个水果取走。
6、自我评价与总结
6.1比较满意之处
在设计这个题目之前,由于对于进程同步的实现方法不是很了解,对于怎样具体实现进程同步有很大的疑问,所以在网上进行了查找,希望找到相关的资料,但几经搜索都没有找到比较适合的材料。
网上的资料主要以P V原语的实现为主,而本实验是以实现进程同步系统的功能为主,因此对于实现功能有一定的帮助,但对于P原语语句与 V原语语句的具体实现并没有给出。
就是在这种虽然有一定基础,但并不能完全依靠的情况下,自己通过查找相关的书籍,了解本系统中可能涉及到的数据结构知识后,成功的实现了进程同步模型系统的功能。
自己对于从对进程同步只是有一个概念上的认识,到最终将它的功能实现这一过程感到满意与欣慰,因为这些都是通过自己的努力一步一步实现的。
在程序设计方面,本程序的数据结构简单,主要包括线程、函数和进程同步中的各种互斥信号和信号量。
程序的数据结构精简,程序设计简介,一目了然。
麻雀虽小,但五脏俱全,凡是实现能够实现该设计功能的组成部分全部包括。
6.2不足之处
首先,虽然熟悉和了解了程序中各数据结构的定义和创建,但是在一些细节问题上还是没有一个很明确的认识,例如虽然知道HANDLE句柄,在程序中可以用于创建线程,但对于其实现的原理还不是很清楚,现在只是机械的合法的使用它。
其次对于Sleep( )函数的理解也不够深刻,在本程序中使用次函数的目的主要是为了进行结果输出时可以将结果以此逐渐的输出,而不是使结果一次性的输出出来,对其在各线程之间是怎样进行操作的并不是很清楚。
最后在运行界面的设计上有些过于简单,输出的信息并不是很详细,与网上一些比较成熟的进程同步的其他模型实现的运行界面相比是比较简陋的,各线程在使用过资源后,资源部的情况,各信号量的变化并没有很具体的显示出来,当
然在以后的设计中会更加的完善。
6.3本次课程设计的收获
本程序是用来实现进程同步模型系统,其核心部分就是如何利用P V原语的原理以及C++的编程语言将线程的同步与互斥操作实现。
所以实现这一功能只需要将线程这一概念理解清楚并熟练运用即可,并不需要其他非常复杂的数据结构和编译环境。
对于我而言重点则在于对线程这一数据结构的理解。
刚开始设计该程序的时候,虽然拥有了了线程的同步与互斥的理论基础和P V原语的实现原理,但对于这些知识的具体实现还是没有头绪,在查阅了很多关于生产者消费者的一些源程序后,看到了关于线程等的一些数据结构的定义、创建和使用方法,但还是由于没有像书上那样进行讲解所以并没有看懂,所以在找不到相关源程序后,我查阅了与VC++相关的书籍,在仔细学习了线程这一数据结构之后,便对于那些经典的生产者消费者问题有进一步的了解。
这个程序的编写是在《VC++ 深入详解》这本书中关于简单多线程程序的一个例子的基础上改编过来的,这个例子只是实现了几个简单多线程的互斥操作,所以我利用P V原语的原理在互斥的基础上添加了同步操作的成分。
当然也只是将最基本的同步操作实现语句添加了进去。
不过在调试编译之后便成功运行了。
这次课程设计让我初步的了解了线程的相关知识,并将进程同步的这一进程之间的操作实现了,对我自己来说是一个小小的突破,理解了线程这一重要概念之后对于我今后更深入的了解计算机的各种操作系统的运行有了很大的帮助。
当然在今后的一段时间里,我不但要充分理解课本上的知识更要进一步的扩展自己在这方面的知识面,为以后自己能够熟练的应用做准备。
与此同时,我要多进行代码的编写,这样不仅可以锻炼自己解决实际问题的能力,同时还可以锻炼自己从整体上分析和设计程序的能力。
6.4其他方法
进程同步的实现可以使用2种方法,一是在windows系统环境下使用线程来实现,二是在linux系统环境下使用进程来实现。
由于在我自己的电脑上只安装
了windows操作系统,所以使用的是第一种方法。
当然如果安装了linux操作系统的话,更应该在该系统下利用进程来实现,这样做可以更好的理解和消化老师在课上所讲的和各次实验容所涉及到的知识。
虽然实现的环境和方法不同,但这2种方法都可以很好的实现进程同步模型的功能。
7、参考文献
(1)闵联营、何克右《C++程序设计教程》理工大学 2005年7月第1版(2)尧学、史美林、高《计算机操作系统教程》(第三版) 清华大学.2006年10月第3版
(3)宋坤、锐宁、伟明《Visual C++ 开发技术大全》人民邮电2007年3月第1版
(4)鑫、余安萍《VC++ 深入详解》电子工业 2008年4月第1版。