进程同步与互斥哲学家进餐问题.docx
《进程同步与互斥哲学家进餐问题.docx》由会员分享,可在线阅读,更多相关《进程同步与互斥哲学家进餐问题.docx(16页珍藏版)》请在冰豆网上搜索。
![进程同步与互斥哲学家进餐问题.docx](https://file1.bdocx.com/fileroot1/2022-11/16/03cec558-1ee1-42cf-8ddc-8907f89e4d7d/03cec558-1ee1-42cf-8ddc-8907f89e4d7d1.gif)
进程同步与互斥哲学家进餐问题
网络教育学院
《操作系统》课程设计
题目:
进程同步与互斥哲学家进餐问题
学习中心:
层次:
专业:
年级:
年秋季
学号:
学生:
辅导教师:
完成日期:
1.题目要求与开发环境
1.1题目目的与要求
题目的目的:
通过实现哲学家进餐问题的同步深入了解和掌握进程同步和互斥的原理。
题目要求:
简单描述哲学家进餐问题。
可设计五个哲学家,每人都需要一双筷子。
哲学家有两种活动:
吃饭和思考,需要成功设计让每个哲学家能够顺利吃饭。
1.2题目开发环境
系统平台:
Windows7旗舰版
实现语言:
C#
开发工具:
MicrosoftVisualStudio2010
1.3开发原型图
1.4设计界面截图
只是为了体现算法,关键我不会美工,所以界面比较简单
2.总体设计思想以及相关知识
2.1总体设计思想
哲学家的生活就是思考和吃饭,即思考,饿了就吃,吃饱了再思考,循环往复。
要求是:
每一个哲学家只有在拿到位于他左右两侧的筷子后,才能够就餐;哲学家不能拿着一只筷子不放手,也不能从其他哲学家手中抢夺筷子;哲学家每次吃饱后必须放下他手中的两只筷子恢复思考,不能强抓住筷子不放。
设计一个程序,能够显示当前各哲学家的状态和桌上筷子的使用情况,并能无死锁的推算出下一状态各哲学家的状态和桌上筷子的使用情况。
即设计一个能安排哲学家正常生活的程序。
开始本来是准备用C++设计的,但是最近开始自学C#,发现微软封装了很多基类,调用十分方便。
可以很简单的设计出程序,正好练习一下,所以就用C#设计程序了,同时在XX查找了很多资料。
2.2本程序涉及到的概念
2.2.1简介
进程同步是一个操作系统级别的概念,是在多道程序的环境下,存在着不同的制约关系,为了协调这种互相制约的关系,实现资源共享和进程协作,从而避免进程之间的冲突,引入了进程同步。
2.2.2临界资源
在操作系统中,进程是占有资源的最小单位(线程可以访问其所在进程内的所有资源,但线程本身并不占有资源或仅仅占有一点必须资源)。
但对于某些资源来说,其在同一时间只能被一个进程所占用。
这些一次只能被一个进程所占用的资源就是所谓的临界资源。
典型的临界资源比如物理上的打印机,或是存在硬盘或内存中被多个进程所共享的一些变量和数据等(如果这类资源不被看成临界资源加以保护,那么很有可能造成丢数据的问题)。
对于临界资源的访问,必须是互诉进行。
也就是当临界资源被占用时,另一个申请临界资源的进程会被阻塞,直到其所申请的临界资源被释放。
而进程内访问临界资源的代码被成为临界区。
对于临界区的访问过程分为四个部分:
1.进入区:
查看临界区是否可访问,如果可以访问,则转到步骤二,否则进程会被阻塞
2.临界区:
在临界区做操作
3.退出区:
清除临界区被占用的标志
4.剩余区:
进程与临界区不相关部分的代码
2.2.3进程同步
进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。
进程间的直接制约关系来源于他们之间的合作。
比如说进程A需要从缓冲区读取进程B产生的信息,当缓冲区为空时,进程B因为读取不到信息而被阻塞。
而当进程A产生信息放入缓冲区时,进程B才会被唤醒。
概念如下图所示。
2.2.4进程互斥
进程互斥是进程之间的间接制约关系。
当一个进程进入临界区使用临界资源时,另一个进程必须等待。
只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。
比如进程B需要访问打印机,但此时进程A占有了打印机,进程B会被阻塞,直到进程A释放了打印机资源,进程B才可以继续执行。
概念如下图所示。
2.2.5实现临界区互斥的基本方法
硬件实现方法
通过硬件实现临界区最简单的办法就是关CPU的中断。
从计算机原理我们知道,CPU进行进程切换是需要通过中断来进行。
如果屏蔽了中断那么就可以保证当前进程顺利的将临界区代码执行完,从而实现了互斥。
这个办法的步骤就是:
屏蔽中断--执行临界区--开中断。
但这样做并不好,这大大限制了处理器交替执行任务的能力。
并且将关中断的权限交给用户代码,那么如果用户代码屏蔽了中断后不再开,那系统岂不是跪了?
还有硬件的指令实现方式,这个方式和接下来要说的信号量方式如出一辙。
但是通过硬件来实现,这里就不细说了。
信号量实现方式
这也是我们比较熟悉PV操作。
通过设置一个表示资源个数的信号量S,通过对信号量S的P和V操作来实现进程的的互斥。
P和V操作分别来自荷兰语Passeren和Vrijgeven,分别表示占有和释放。
PV操作是操作系统的原语,意味着具有原子性。
P操作首先减少信号量,表示有一个进程将占用或等待资源,然后检测S是否小于0,如果小于0则阻塞,如果大于0则占有资源进行执行。
V操作是和P操作相反的操作,首先增加信号量,表示占用或等待资源的进程减少了1个。
然后检测S是否小于0,如果小于0则唤醒等待使用S资源的其它进程。
本程序就是用信号量进行实现的。
3.流程和效果图
3.1程序流程图及简介
单击“开始进餐”按钮首先初始化哲学家和筷子对象,然后声明五个进程。
进程逐一开始后判断当前哲学家两侧的筷子是否无人使用,如果无人使用则当前哲学家开始进餐,并改变程序界面哲学家标签的文字为“哲学家i开始进餐”,同时更改哲学家两侧筷子标签为“哲学家i拿起筷子”,哲学家文字后面的变量i为当前哲学家编号。
为了防止长时间谁也拿不到筷子,暂停进程1.5秒。
1.5秒后当前哲学家停止进餐开始思考,并释放两侧筷子的资源,更改哲学家标签为“哲学家i在思考”,更改哲学家两侧筷子标签为“无人使用的筷子”。
I为哲学家编号变量。
当一个哲学家完成吃饭、思考的过程后,重新进去排队,等待两侧的筷子资源被别的哲学家释放,进入下一个循环。
如下图所示:
3.2流程图各阶段程序界面的变化
程序设计界面
开始运行程序,并初始化哲学家和筷子对象状态
单击开始进餐按钮以后
判断哲学家两侧的筷子为无人使用状态时,哲学家开始进餐,并改变标签文字
哲学家进餐后进入思考状态,并释放两侧的筷子
4.程序源代码
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.Threading;
namespacePhEating
{
///
///进程同步与互斥哲学家进餐问题
///
publicpartialclassMainForm:
Form
{
privateMutex[]m_chopsticksMux;//筷子对象
privateThread[]m_thread;
privateLabel[]m_phInfo;//哲学家标签
privateLabel[]m_chopInfo;//筷子标签
privateSynchronizationContextm_context;
privateboolm_isRunning=true;
///
///哲学家对象
///
publicclassPhilospher
{
//哲学家名字
publicStringm_name;
//哲学家拿到手里的筷子
publicChopStickm_left;
publicChopStickm_right;
//哲学家编号
publicintm_index;
//释放双手的筷子
publicvoidRelease()
{
m_left.Release();
m_right.Release();
}
}
///
///筷子对象
///
publicclassChopStick
{
publicMutexm_mutex;
publicintm_number;
publicvoidRelease()
{
m_mutex.ReleaseMutex();
}
}
publicMainForm()
{
InitializeComponent();
m_context=SynchronizationContext.Current;
m_phInfo=newLabel[5];
m_phInfo[0]=label1;
m_phInfo[1]=label2;
m_phInfo[2]=label3;
m_phInfo[3]=label4;
m_phInfo[4]=label5;
//初始化哲学家状态为思考
for(inti=0;i<5;i++)
{
m_phInfo[i].Text="哲学家"+(i+1)+":
在思考";
m_phInfo[i].BackColor=Color.Gray;
}
m_chopInfo=newLabel[5];
m_chopInfo[0]=label6;
m_chopInfo[1]=label7;
m_chopInfo[2]=label8;
m_chopInfo[3]=label9;
m_chopInfo[4]=label10;
//初始化筷子状态为无人使用
for(inti=0;i<5;i++)
{
m_chopInfo[i].Text="无人使用的筷子";
}
}
//单击开始进餐按钮
privatevoidbutton1_Click(objectsender,EventArgse)
{
m_chopsticksMux=newMutex[5];
m_thread=newThread[5];
for(inti=0;i<5;i++)
{
m_chopsticksMux[i]=newMutex(true,"筷子"+i.ToString());
}
ParameterizedThreadStartpts;
for(inti=0;i<5;i++)
{
pts=newParameterizedThreadStart(Eating);
m_thread[i]=newThread(pts);
}
Philospherph=newPhilospher();
ph.m_name="哲学家1";
ph.m_index=0;
ChopStickcsl=newChopStick();
csl.m_number=4;
csl.m_mutex=m_chopsticksMux[4];
ph.m_left=csl;
ChopStickcsr=newChopStick();
csr.m_number=