进程同步互斥——不死锁的哲学家问题
2014-06-16 23:55
411 查看
一、需求分析
(1)本程序模拟不死锁的哲学家问题,将哲学家们的活动过程以文字及可视化的方式表示出来。
(2)本程序的运行不需要输入测试数据,在程序运行是会提示选择程序的运行频率,选择运行频率后点击“开始”按钮,程序会自动模拟哲学家就餐问题,通过随机数决定哲学家的思考时间和进餐时间。点击“返回选择运行频率”可以重新选择运行的速度,点击“结束”则退出程序。
(3)程序的输出形式为可视化和文字两种。模拟哲学家就餐问题不断变换图片和文字,图片与文字各有3种:进餐、饥饿、进食。例如哲学家1此时正在进食,则会在哲学家1的位置上显示“进食”的图片,显示文字“哲学家1正在进食!”。
二、概要设计
(1)采用Java中的Thread类来实现5个线程并发执行;定义一个一维数组philosopher[5],来表示5个哲学家的状态,-1为饥饿,0为思考,1为进食,例如philosopher[0]=0表示第一个哲学家正在思考;定义一个Chopsticks类,表示信号量“筷子”;定义一个Philo类,表示第n个哲学家先拿first筷子再拿late筷子(根据死锁解决方法:奇数号人先拿左叉,偶数号人先拿右叉)。
(2)本程序共有5个模块,分别如下:
1、Philosopher( ) 显示“选择频率”界面
2、Go( ) 根据选择的频率,显示程序的主界面即模拟界面
3、Panel( ) 程序的绘图面板,用于变换图片和变换文字
4、Chopsticks 该类代表信号量
5、Philo 该类继承Threa类,使得5个进程并发执行
6、main( ) 调用Philosopher( ),开始运行程序
三、详细设计
(1)int[] philosopher = new int [5];//5个哲学家的现状,-1为饥饿,0为思考,1为进食
(2)static int speed;//设定一个静态变量speed,以记录选择的程序运行频率
(3)主函数:main( )
输入值:无
返回值:无
调用模块:Philosopher( )
详细设计:
public static void main(String[] args){ //调用Philosopher( ),开始运行程序
new Philosopher();
}
(4)程序开始选择运行频率模块:Philosopher( )
输入值:点击按钮“快”、“中”、“慢”,选择程序运行的频率
4000
返回值:无
调用模块:Go( )
详细设计:
JFrame frame = new JFrame("选择频率"); //建立一个“选择频率”对话框
//为对话框设定参数
//设置3个按钮“快”、“中”、“慢”,表示程序运行的频率
//为3个按钮设定监听函数,根据选择频率的不同设置speed的值,并调用Go( )
(5)程序的主界面,模拟界面模块:Go( )
输入值:点击按钮“开始”、“结束”、“返回选择运行频率”,选择操作
返回值:无
调用模块:Philo( )、Philosopher( )
详细设计:
//为界面设定参数
//定义3个按钮“开始”、“结束”、“返回选择运行频率”
//设定3个按钮的监听函数
if(点击的按钮是“开始”)
then 调用Philo( ),让5个线程开始工作
if(点击的按钮是“结束”)
then 退出程序
if(点击的按钮是“返回选择运行频率”)
then 调用Philosopher( ),重新选择程序运行频率
(6)使5个线程并行工作的类模块:Philo
输入值:n表示第几个哲学家、first表示先拿的筷子、late表示后拿的筷子
返回值:无
调用模块:无
详细设计:
//重写Thread类的run( )方法
while(true){
//随机一个数random
philosopher
= 0;//令第n个哲学家的状态为正在思考,并暂停random时间
sleep(random);
philosopher
= -1//令第n个哲学家的状态为正在饥饿,并申请信号量“筷子”
first.semwait();
late.semwait();
philosopher
= 1;//令第n个哲学家的状态为正在进食,暂停,并释放信号量
first.semsignal();
late.semsignal();
}
(7)信号量类:Chopsticks
输入值:无
返回值:无
调用模块:无
详细设计:
int flag = 0;//设置信号量flag
//写申请信号量函数semwait( )
//写释放信号量函数semsignal( )
(8)绘图面板类:Panel
输入值:philosopher[5]的值表示各个哲学家的状态
返回值:图片和文字根据程序的运行模拟哲学家就餐问题不断变化
调用模块:无
详细设计:
//读取图片
//画一个圆表示圆桌
//在圆桌上标上数字标志第几位哲学家
//根据每位哲学家的状态作出相应的变化
//如第一位哲学家:
if(哲学家1的状态为正在饥饿)
then{
//界面刷新
//变换文字为“哲学家1正在饥饿!”
//将哲学家1位置上的图片变换为“饥饿”图片
}else if(哲学家1的状态为正在思考)
then{
//界面刷新
//变换文字为“哲学家1正在思考!”
//将哲学家1位置上的图片变换为“思考”图片
}else if(哲学家1的状态为正在进食、哲学家2的状态为不在进食以及哲学家5的
状态为不在进食)
then{
//界面刷新
//变换文字为“哲学家1正在进食!”
//将哲学家1位置上的图片变换为“进食”图片
}
四、调试分析
(1)调试过程中遇到的问题是如何解决的以及对设计与实现的讨论和分析:
在编码调试的过程中,我共遇到了一下个问题。第一个是图片和文字的变换速度
太快。原因是在进食和思考的时候暂停的时间太断,因此这个问题是比较容易解 决的,只要修改Philo类中的sleep( )中的数值就行,经过几次的调试后终于将速度
控制好,这也使我想到了加入控制程序运行频率这一功能。第二个是程序在点击“开 始”之后,界面没有变化,而将窗口最小化或移动时,界面才会发生变化。在查询 了网上的资料后我知道了是在每一次变化的时候我没有刷新页面,因此我在每一个 会引起界面变化的语句后加上了repaint,使得每次变化都会自己刷新界面,使得画 面看起来有动态感。第三个是当我在利用自由布局管理器的时候,发现有些按钮会
消失,后来我发现是我在设置面板大小的时候没有注意,导致面板挡住了按钮,改 小了大小之后就成功地解决了这个问题。
(2)算法的时间复杂性和改进设想:
此程序由于是不间断的,因此只考虑一次的时间复杂性。此算法的时间复杂性为 O(n) 。如果能在每一次变化前都自动发觉参数的变化,那就不用每一次都检查每 位哲学家的状态,应该会降低时间复杂性。
六、测试与运行结果
(1)选择程序运行频率
![](http://img.blog.csdn.net/20140616235310390?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRThBMUY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(2)程序初始界面
![](http://img.blog.csdn.net/20140616235323500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRThBMUY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(3)点击“开始”按钮后,程序运行界面1
![](http://img.blog.csdn.net/20140616235340906?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRThBMUY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(4)程序运行界面2
![](http://img.blog.csdn.net/20140616235404765?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRThBMUY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(5)程序运行界面3
![](http://img.blog.csdn.net/20140616235423140?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRThBMUY2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(需要源代码请联系我)
(1)本程序模拟不死锁的哲学家问题,将哲学家们的活动过程以文字及可视化的方式表示出来。
(2)本程序的运行不需要输入测试数据,在程序运行是会提示选择程序的运行频率,选择运行频率后点击“开始”按钮,程序会自动模拟哲学家就餐问题,通过随机数决定哲学家的思考时间和进餐时间。点击“返回选择运行频率”可以重新选择运行的速度,点击“结束”则退出程序。
(3)程序的输出形式为可视化和文字两种。模拟哲学家就餐问题不断变换图片和文字,图片与文字各有3种:进餐、饥饿、进食。例如哲学家1此时正在进食,则会在哲学家1的位置上显示“进食”的图片,显示文字“哲学家1正在进食!”。
二、概要设计
(1)采用Java中的Thread类来实现5个线程并发执行;定义一个一维数组philosopher[5],来表示5个哲学家的状态,-1为饥饿,0为思考,1为进食,例如philosopher[0]=0表示第一个哲学家正在思考;定义一个Chopsticks类,表示信号量“筷子”;定义一个Philo类,表示第n个哲学家先拿first筷子再拿late筷子(根据死锁解决方法:奇数号人先拿左叉,偶数号人先拿右叉)。
(2)本程序共有5个模块,分别如下:
1、Philosopher( ) 显示“选择频率”界面
2、Go( ) 根据选择的频率,显示程序的主界面即模拟界面
3、Panel( ) 程序的绘图面板,用于变换图片和变换文字
4、Chopsticks 该类代表信号量
5、Philo 该类继承Threa类,使得5个进程并发执行
6、main( ) 调用Philosopher( ),开始运行程序
三、详细设计
(1)int[] philosopher = new int [5];//5个哲学家的现状,-1为饥饿,0为思考,1为进食
(2)static int speed;//设定一个静态变量speed,以记录选择的程序运行频率
(3)主函数:main( )
输入值:无
返回值:无
调用模块:Philosopher( )
详细设计:
public static void main(String[] args){ //调用Philosopher( ),开始运行程序
new Philosopher();
}
(4)程序开始选择运行频率模块:Philosopher( )
输入值:点击按钮“快”、“中”、“慢”,选择程序运行的频率
4000
返回值:无
调用模块:Go( )
详细设计:
JFrame frame = new JFrame("选择频率"); //建立一个“选择频率”对话框
//为对话框设定参数
//设置3个按钮“快”、“中”、“慢”,表示程序运行的频率
//为3个按钮设定监听函数,根据选择频率的不同设置speed的值,并调用Go( )
(5)程序的主界面,模拟界面模块:Go( )
输入值:点击按钮“开始”、“结束”、“返回选择运行频率”,选择操作
返回值:无
调用模块:Philo( )、Philosopher( )
详细设计:
//为界面设定参数
//定义3个按钮“开始”、“结束”、“返回选择运行频率”
//设定3个按钮的监听函数
if(点击的按钮是“开始”)
then 调用Philo( ),让5个线程开始工作
if(点击的按钮是“结束”)
then 退出程序
if(点击的按钮是“返回选择运行频率”)
then 调用Philosopher( ),重新选择程序运行频率
(6)使5个线程并行工作的类模块:Philo
输入值:n表示第几个哲学家、first表示先拿的筷子、late表示后拿的筷子
返回值:无
调用模块:无
详细设计:
//重写Thread类的run( )方法
while(true){
//随机一个数random
philosopher
= 0;//令第n个哲学家的状态为正在思考,并暂停random时间
sleep(random);
philosopher
= -1//令第n个哲学家的状态为正在饥饿,并申请信号量“筷子”
first.semwait();
late.semwait();
philosopher
= 1;//令第n个哲学家的状态为正在进食,暂停,并释放信号量
first.semsignal();
late.semsignal();
}
(7)信号量类:Chopsticks
输入值:无
返回值:无
调用模块:无
详细设计:
int flag = 0;//设置信号量flag
//写申请信号量函数semwait( )
//写释放信号量函数semsignal( )
(8)绘图面板类:Panel
输入值:philosopher[5]的值表示各个哲学家的状态
返回值:图片和文字根据程序的运行模拟哲学家就餐问题不断变化
调用模块:无
详细设计:
//读取图片
//画一个圆表示圆桌
//在圆桌上标上数字标志第几位哲学家
//根据每位哲学家的状态作出相应的变化
//如第一位哲学家:
if(哲学家1的状态为正在饥饿)
then{
//界面刷新
//变换文字为“哲学家1正在饥饿!”
//将哲学家1位置上的图片变换为“饥饿”图片
}else if(哲学家1的状态为正在思考)
then{
//界面刷新
//变换文字为“哲学家1正在思考!”
//将哲学家1位置上的图片变换为“思考”图片
}else if(哲学家1的状态为正在进食、哲学家2的状态为不在进食以及哲学家5的
状态为不在进食)
then{
//界面刷新
//变换文字为“哲学家1正在进食!”
//将哲学家1位置上的图片变换为“进食”图片
}
四、调试分析
(1)调试过程中遇到的问题是如何解决的以及对设计与实现的讨论和分析:
在编码调试的过程中,我共遇到了一下个问题。第一个是图片和文字的变换速度
太快。原因是在进食和思考的时候暂停的时间太断,因此这个问题是比较容易解 决的,只要修改Philo类中的sleep( )中的数值就行,经过几次的调试后终于将速度
控制好,这也使我想到了加入控制程序运行频率这一功能。第二个是程序在点击“开 始”之后,界面没有变化,而将窗口最小化或移动时,界面才会发生变化。在查询 了网上的资料后我知道了是在每一次变化的时候我没有刷新页面,因此我在每一个 会引起界面变化的语句后加上了repaint,使得每次变化都会自己刷新界面,使得画 面看起来有动态感。第三个是当我在利用自由布局管理器的时候,发现有些按钮会
消失,后来我发现是我在设置面板大小的时候没有注意,导致面板挡住了按钮,改 小了大小之后就成功地解决了这个问题。
(2)算法的时间复杂性和改进设想:
此程序由于是不间断的,因此只考虑一次的时间复杂性。此算法的时间复杂性为 O(n) 。如果能在每一次变化前都自动发觉参数的变化,那就不用每一次都检查每 位哲学家的状态,应该会降低时间复杂性。
六、测试与运行结果
(1)选择程序运行频率
(2)程序初始界面
(3)点击“开始”按钮后,程序运行界面1
(4)程序运行界面2
(5)程序运行界面3
(需要源代码请联系我)
相关文章推荐
- 单车道问题 - 进程同步互斥与死锁问题的解决
- 进程、线程知识点总结和同步(消费者生产者,读者写者三类问题)、互斥、异步、并发、并行、死锁、活锁的总结
- 进程(线程)间同步互斥经典问题(二)哲学家问题
- 进程的同步与互斥-哲学家问题
- 进程、线程知识点总结和同步(消费者生产者,读者写者三类问题)、互斥、异步、并发、并行、死锁、活锁的总结
- 信号量---解决进程间的同步与互斥问题之1
- 操作系统经典同步互斥问题——哲学家就餐
- 操作系统进程同步互斥经典问题之读者写者问题
- 进程(线程)间同步互斥问题(三) 熟睡的理发师问题
- 同步和互斥的一些问题(死锁,优先级逆转)
- 进程同步及避免死锁经典问题
- 进程(线程)间同步互斥问题(四) 三个烟鬼问题
- 进程间同步互斥经典问题(一)生产者-消费者问题
- 三个同步与互斥问题之哲学家就餐
- 黑马程序员_同步过程的死锁问题(哲学家难题)
- 进程同步互斥经典题之消费者与生产者问题
- linux网络编程之System V 信号量(二):用信号量实现进程互斥示例和解决哲学家就餐问题
- 同步和互斥的一些问题(死锁,优先级逆转)
- 操作系统进程同步三大问题:生产者消费者,哲学家进餐,读者写者问题
- Linux环境下线程的同步与互斥以及死锁问题