打印

强烈要求大家都来讨论!如何解决解决哲学家吃饭问题

[复制链接]
25590|137
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
singleywy|  楼主 | 2011-3-14 18:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 singleywy 于 2011-3-15 20:13 编辑

下面有相关讨论,请大家发表自己的看法呀:

原本想在原帖上继续发表,由于翻页看是在麻烦,不如新开一个贴,大家共同探讨,问题来源于,刘前辈;
他给出这样一个题目:

5个指示灯代表5个哲学家。显然,任何时候只能有一个或者2个灯亮,而且不可能是邻近的2个灯亮。

假定每个哲学家吃饭时间2秒钟,不需要其他条件了吧。

计算机操作系统中的原题为:
5个哲学家围在一起吃饭,哲学家之间放着,交叉放着叉子或汤勺,即3个叉子、2个汤勺或者2个叉子、3个汤勺,每个哲学家,仅当身旁的叉子与汤勺都未被使用时才能吃饭;现在5个哲学家就相当于5个LED灯;

依照刘前辈的意思,转化为中国文化为:
每个哲学家之间放着一只筷子,只有左右拿起一双筷子才可以开吃。


现在,采用smartrtos中的系统函数解决问题;顺便向大家介绍其中函数的使用;

相关帖子

来自 2楼
刘前辈| | 2011-3-15 18:15 | 只看该作者
本帖最后由 刘前辈 于 2011-3-15 18:32 编辑

我为什么说你的是错的:因为你把2只筷子分裂为2个资源,而且不在同一个临界区了。所以,从OS并发角度,死锁条件就来了。见教材: 确实有很多种方法解这个经典问题,但是基本前提就是2个资源同时获取,同时释放。所有教材都说了你所采用的方法可能造成死锁。是简单错误的,大多数人都是这么考虑问题的。结果有些事他们没想到。

哲学家就餐.pdf

219.35 KB

使用特权

评论回复
来自 3楼
highgear| | 2011-3-16 08:58 | 只看该作者
哲学家就餐问题是大学本科三年级的作业题。

哲学家就餐问题是在计算机科学中的一个经典问题,用来演示在并行计算中多线程同步(Synchronization)时产生的问题。

在1971年,著名的计算机科学家艾兹格·迪科斯彻提出了一个同步问题,即假设有五台计算机都试图访问五份共享的磁带驱动器。稍后,这个问题被托尼·霍尔重新表述为哲学家就餐问题。这个问题可以用来解释死锁和资源耗尽。

解法

[编辑] 服务生解法

一个简单的解法是引入一个餐厅服务生,哲学家必须经过他的允许才能拿起餐叉。因为服务生知道哪只餐叉正在使用,所以他能够作出判断避免死锁。

为了演示这种解法,假设哲学家依次标号为A至E。如果A和C在吃东西,则有四只餐叉在使用中。B坐在A和C之间,所以两只餐叉都无法使用,而D和E之间有一只空余的餐叉。假设这时D想要吃东西。如果他拿起了第五只餐叉,就有可能发生死锁。相反,如果他征求服务生同意,服务生会让他等待。这样,我们就能保证下次当两把餐叉空余出来时,一定有一位哲学家可以成功的得到一对餐叉,从而避免了死锁。

[编辑] 资源分级解法

另一个简单的解法是为资源(这里是餐叉)分配一个偏序或者分级的关系,并约定所有资源都按照这种顺序获取,按相反顺序释放,而且保证不会有两个无关资源同时被同一项工作所需要。在哲学家就餐问题中,资源(餐叉)按照某种规则编号为1至5,每一个工作单元(哲学家)总是先拿起左右两边编号较低的餐叉,再拿编号较高的。用完餐叉后,他总是先放下编号较高的餐叉,再放下编号较低的。在这种情况下,当四位哲学家同时拿起他们手边编号较低的餐叉时,只有编号最高的餐叉留在桌上,从而第五位哲学家就不能使用任何一只餐叉了。而且,只有一位哲学家能使用最高编号的餐叉,所以他能使用两只餐叉用餐。当他吃完后,他会先放下编号最高的餐叉,再放下编号较低的餐叉,从而让另一位哲学家拿起后边的这只开始吃东西。

尽管资源分级能避免死锁,但这种策略并不总是实用的,特别是当所需资源的列表并不是事先知道的时候。例如,假设一个工作单元拿着资源3和5,并决定需要资源2,则必须先要释放5,之后释放3,才能得到2,之后必须重新按顺序获取3和5。对需要访问大量数据库记录的计算机程序来说,如果需要先释放高编号的记录才能访问新的记录,那么运行效率就不会高,因此这种方法在这里并不实用。

这种方法经常是实际计算机科学问题中最实用的解法,通过为分级锁指定常量,强制获得锁的顺序,就可以解决这个问题。

[编辑] Chandy/Misra解法

1984年,K. Mani Chandy和J. Misra提出了哲学家就餐问题的另一个解法,允许任意的用户(编号P1, ..., Pn)争用任意数量的资源。与迪科斯彻的解法不同的是[來源請求],这里编号可以是任意的。
1.对每一对竞争一个资源的哲学家,新拿一个餐叉,给编号较低的哲学家。每只餐叉都是“干净的”或者“脏的”。最初,所有的餐叉都是脏的。
2.当一位哲学家要使用资源(也就是要吃东西)时,他必须从与他竞争的邻居那里得到。对每只他当前没有的餐叉,他都发送一个请求。
3.当拥有餐叉的哲学家收到请求时,如果餐叉是干净的,那么他继续留着,否则就擦干净并交出餐叉。
4.当某个哲学家吃东西后,他的餐叉就变脏了。如果另一个哲学家之前请求过其中的餐叉,那他就擦干净并交出餐叉。

这个解法允许很大的并行性,适用于任意大的问题。

http://zh.wikipedia.org/zh/%E5%9 ... 0%E9%97%AE%E9%A2%98

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
123jj + 1
地板
singleywy|  楼主 | 2011-3-14 18:26 | 只看该作者
此次涉及到的函数有:
OsSemP(uint8 index,uint8 timetick)
例子:OsSemP(0,255),表示申请信号量0,如果信号量不为0,则信号量减1,返回信号量;如果信号量为0,则将该当前任务插入等待列表,直至信号量0可以使用;
其中timetick的含义:
timetick==0时,表示无论信号量是否可取,立即返回;
timetick==255时,表示信号量不可取时,无限等待直至信号量可使用;
timetick为其他值时,表示信号量不可取时,超时等待,直至时钟结束,或者信号量可获取;
OsSemV(uint8 index)
例子:OsSemV(0),表示释放当前信号量0,如果有优先级高的任务等待信号0,则进行任务切换,否则信号量加1

使用特权

评论回复
5
singleywy|  楼主 | 2011-3-14 18:38 | 只看该作者
本帖最后由 singleywy 于 2011-3-14 18:48 编辑

现在,5个LED1--LED5代表了5个哲学家,而叉子或汤勺代表5个资源;
其中有一个问题,因为哲学家都是平等的,不可能你我都争着吃饭,必须要有一个哲学家先吃饭,或者两个哲学家先吃饭,这就是初始值的问题,这问题我与刘前辈争论了很久,现在,我把初始值的意义指出来;
另一点就是,每个哲学家必须同时获得了两个资源才可以吃饭,如果每个哲学家都占据了一个资源,都必将是无解之题

所以下面,我将从三种初始值来探讨这个问题;
0)哲学家同时吃饭,即同时占据一个资源,此题无解,没有灯亮;
1)有1个哲学家先吃饭,此题有解;
2)有2个哲学家先吃饭,此题有解;

使用特权

评论回复
6
singleywy|  楼主 | 2011-3-14 18:40 | 只看该作者
不知,刘前辈,现在是否理解我先前说的话,可能是我先前在表述上有错误,导致您很多的误解

使用特权

评论回复
7
singleywy|  楼主 | 2011-3-14 18:45 | 只看该作者
本帖最后由 singleywy 于 2011-3-14 18:50 编辑

现在使用smartrtos系统,来解决这个哲学问题;
其中信号量0---4代表五个资源,LED1---LED5代表五个哲学家:
采用信号量的方式来解决这个问题;

情况2,有2个哲学家先吃饭,即初始值为两个哲学家先吃饭;
开发板上的显示结果是,有两个LED在亮,并呈现交替性流动;

比如这个例程:   
#include<reg52.h>
#include "Os_api.h"
#include"IOfor52.h"
void OsTimerISR()interrupt 1
{
        OsIntEnter();
#if T0_TIMER_EN        
        ACC=((65536+8-SYS_CLK)%256);
        TR0=0;
        TL0+=ACC;
        ACC=0;
        CY=ACC&0x80;
        ACC =((65536+8-SYS_CLK)/256)+ACC;
        TH0+=ACC;
        TR0=1;        //时间管理
#endif
#if T2_TIMER_EN
#endif
#if TIME_EXPAND_EN
    OsRunTime--;
        if(OsRunTime == 0){
                OsRunTime=TIME_COEFFICIENT-1;
                OsTimeTick();
        }
#else
    OsTimeTick();
#endif
        OsIntExit();                                
}

void TaskA()
{
        while(1)
        {
                OsSemP(4,255);//无限等待,获取信号量4
                OsSemP(0,255);//无限等待,获取信号量0
                LED1_ON;
                OsTaskWait(DO_TMO,200);
                LED1_OFF;
                OsSemV(0);//释放信号量0
                OsSemV(4);//释放信号量4
        }
}


void TaskB()
{
   while(1)
   {
                OsSemP(0,255);//无限等待,获取信号量0
                OsSemP(1,255);//无限等待,获取信号量1
                LED2_ON;
                OsTaskWait(DO_TMO,200);
                LED2_OFF;
                OsSemV(1);//释放信号量1
                OsSemV(0);//释放信号量0
   }
}
void TaskC()
{
        while(1)
        {
                OsSemP(1,255);//无限等待,获取信号量1
                OsSemP(2,255);//无限等待,获取信号量2
                LED3_ON;
                OsTaskWait(DO_TMO,200);
                LED3_OFF;
                OsSemV(2);//释放信号量2
                OsSemV(1);//释放信号量1
        }
}
void TaskD()
{
        while(1)
        {
                OsSemP(2,255);//无限等待,获取信号量2
                OsSemP(3,255);//无限等待,获取信号量3
                LED4_ON;
                OsTaskWait(DO_TMO,200);
                LED4_OFF;
                OsSemV(3);//释放信号量3
                OsSemV(2);//释放信号量2
        }
}
void TaskE()
{
        while(1)
        {
                OsSemP(4,255);//无限等待,获取信号量4
                OsSemP(3,255);//无限等待,获取信号量3
                LED5_ON;
                OsTaskWait(DO_TMO,200);
                LED5_OFF;
                OsSemV(3);//释放信号量3
                OsSemV(4);//释放信号量4
        }

}
void TaskIdle()
{
         static uint8 i;
         LED0_ON;
         OsSemCreate(0,1);//创建信号量0,初始值为1;
         OsSemCreate(1,1);//创建信号量1,初始值为1;
         OsSemCreate(2,1);//创建信号量2,初始值为1;
         OsSemCreate(3,1);//创建信号量3,初始值为1;
         OsSemCreate(4,1);//创建信号量4,初始值为1;
         while(1)
         {
                 i++;
                LED0=LED0^1;
         }

}
void main()
{
        OsTaskCreate(0,(uint16)TaskA);
        OsTaskCreate(1,(uint16)TaskB);
        OsTaskCreate(2,(uint16)TaskC);
        OsTaskCreate(3,(uint16)TaskD);
        OsTaskCreate(4,(uint16)TaskE);
        OsTaskStart(5,(uint16)TaskIdle);
}

使用特权

评论回复
8
刘前辈| | 2011-3-14 18:52 | 只看该作者
如果每个哲学家都占据了一个资源,都必将是无解之题


LZ抓到了问题的本质,正是因为这一点。所以称为经典问题。但是别人就能解。
    现实中解决方案不是很简单么?一个哲学家如果发现他需要的资源不同时具备,他就“一个也不取。让给别人。”——“要么都获取,要么一个也不取。”(我们老师的口头禅)这么简单的规则,最简单的OS都能解。关键是怎么写程序,国外OS教材书上都有解决方案。
     谁说无解之题?


、、

使用特权

评论回复
9
singleywy|  楼主 | 2011-3-14 18:55 | 只看该作者
情况1)有1个哲学家先吃饭,即初始值为1个哲学家先吃饭
在开发板上显示的结果为:时而1个LED灯亮,时而2个LED灯亮
例程如下:
#include<reg52.h>
#include "Os_api.h"
#include"IOfor52.h"
void OsTimerISR()interrupt 1
{
        OsIntEnter();
#if T0_TIMER_EN       
        ACC=((65536+8-SYS_CLK)%256);
        TR0=0;
        TL0+=ACC;
        ACC=0;
        CY=ACC&0x80;
        ACC =((65536+8-SYS_CLK)/256)+ACC;
        TH0+=ACC;
        TR0=1;        //时间管理
#endif
#if T2_TIMER_EN
#endif
#if TIME_EXPAND_EN
    OsRunTime--;
        if(OsRunTime == 0){
                OsRunTime=TIME_COEFFICIENT-1;
                OsTimeTick();
        }
#else
    OsTimeTick();
#endif
        OsIntExit();                               
}

void TaskA()
{
        while(1)
        {
                OsSemP(4,255);//无限等待,获取信号量4
                OsSemP(0,255);//无限等待,获取信号量0
                LED1_ON;
                OsTaskWait(DO_TMO,200);
                LED1_OFF;
                OsSemV(0);//释放信号量0
                OsSemV(4);//释放信号量4
        }
}


void TaskB()
{
   while(1)
   {
                OsSemP(1,255);//无限等待,获取信号量0
                OsSemP(0,255);//无限等待,获取信号量1
                LED2_ON;
                OsTaskWait(DO_TMO,200);
                LED2_OFF;
                OsSemV(1);//释放信号量1
                OsSemV(0);//释放信号量0
   }
}
void TaskC()
{
        while(1)
        {
                OsSemP(2,255);//无限等待,获取信号量1
                OsSemP(1,255);//无限等待,获取信号量2
                LED3_ON;
                OsTaskWait(DO_TMO,200);
                LED3_OFF;
                OsSemV(2);//释放信号量2
                OsSemV(1);//释放信号量1
        }
}
void TaskD()
{
        while(1)
        {
                OsSemP(3,255);//无限等待,获取信号量2
                OsSemP(2,255);//无限等待,获取信号量3
                LED4_ON;
                OsTaskWait(DO_TMO,200);
                LED4_OFF;
                OsSemV(3);//释放信号量3
                OsSemV(2);//释放信号量2
        }
}
void TaskE()
{
        while(1)
        {
                OsSemP(3,255);//无限等待,获取信号量4
                OsSemP(4,255);//无限等待,获取信号量3
                LED5_ON;
                OsTaskWait(DO_TMO,200);
                LED5_OFF;
                OsSemV(3);//释放信号量3
                OsSemV(4);//释放信号量4
        }

}
void TaskIdle()
{
         static uint8 i;
         LED0_ON;
         OsSemCreate(0,1);//创建信号量0,初始值为1;
         OsSemCreate(1,1);//创建信号量1,初始值为1;
         OsSemCreate(2,1);//创建信号量2,初始值为1;
         OsSemCreate(3,1);//创建信号量3,初始值为1;
         OsSemCreate(4,1);//创建信号量4,初始值为1;
         while(1)
         {
                 i++;
                LED0=LED0^1;
         }

}
void main()
{
        OsTaskCreate(0,(uint16)TaskA);
        OsTaskCreate(1,(uint16)TaskB);
        OsTaskCreate(2,(uint16)TaskC);
        OsTaskCreate(3,(uint16)TaskD);
        OsTaskCreate(4,(uint16)TaskE);
        OsTaskStart(5,(uint16)TaskIdle);
}

使用特权

评论回复
10
singleywy|  楼主 | 2011-3-14 19:01 | 只看该作者
6# 刘前辈
恩,我理解您的意思了,很有意思,好吧,我知道怎么解答了,请您等我的程序

使用特权

评论回复
11
singleywy|  楼主 | 2011-3-14 19:07 | 只看该作者
6# 刘前辈
恩,刘前辈,小弟识浅,受教了

使用特权

评论回复
12
刘前辈| | 2011-3-14 19:10 | 只看该作者
本帖最后由 刘前辈 于 2011-3-14 19:28 编辑
timetick为其他值时,表示信号量不可取时,超时等待,直至时钟结束,或者信号量可获取;


分歧点,LZ这个“直至”肯定表达错了。你的“直至”究竟是不是循环踏步等待?如果不是,那LZ就不应该用“直至”这个词。否则就成了顺序任务了。

所谓“超时等待”,是由内核调度器唤醒的。而LZ的意思一直让人理解为是用户任务管理,——“我不允许别人抢筷子……”

   那叫并发任务么?并发任务的特征就是异步、随机;——不知道什么时候,其他哲学家就把一只筷子拿走了,让哲学家A永远等不到他需要的信号量!他怎么办?LZ并没有让A放下这一只没用的筷子让给别人,死锁条件产生了。
      ——如果总把题目理解为1、2、3、4、5。   根本没关系,只是概念经典。编程是统一的。也就是现实世界中很多同样类似的问题。

LZ写成了专用程序,换一个类似,程序又要重新写。没有标准模式。为解题而解题。

还是那句话:世界经典问题,没那么简单。该犯的错误,咱们都犯过了。于是进步了,提高了。


、、

使用特权

评论回复
13
汽车电子| | 2011-3-14 19:12 | 只看该作者
作个记号,有空再看

使用特权

评论回复
14
刘前辈| | 2011-3-14 19:37 | 只看该作者
信号量是内核对象。没有任何一个信号量是“等待……,直到……”,CPU 绝不会空转等待。

有一种说法是“睡眠在这个信号量上……”P(S)/V(S) 是睡眠/唤醒的关系操作,

使用特权

评论回复
15
singleywy|  楼主 | 2011-3-14 19:42 | 只看该作者
本帖最后由 singleywy 于 2011-3-14 19:59 编辑
信号量是内核对象。没有任何一个信号量是“等待……,直到……”,CPU 绝不会空转等待。

有一种说法是“睡眠在这个信号量上……”P(S)/V(S) 是睡眠/唤醒的关系操作, ...
刘前辈 发表于 2011-3-14 19:37

恩,前辈说的很准确,我在这方面的表述实在欠缺,主要还是自己的认识不够,谢谢您的指教,小辈,收获不浅
分歧点,LZ这个“直至”肯定表达错了。你的“直至”究竟是不是循环踏步等待?如果不是,那LZ就不应该用“直至”这个词。否则就成了顺序任务了。

所谓“超时等待”,是由内核调度器唤醒的。而LZ的意思一直让人理解 ...
刘前辈 发表于 2011-3-14 19:10

恩,是我表述上错误,应为资源不可获取时,任务插入等待列表,挂起等待超时时间到或者信号量可获取,并进行任务切换

不过有一点,因为哲学家是平等的,才用时间片轮流的方式解决此问题,应该好一些,而采用优先级方式调度,貌似人为的给哲学家设定了优先级,使用这种系统来解决这个问题显的有点不合适,不知自己是否理解正确。

使用特权

评论回复
16
singleywy|  楼主 | 2011-3-14 20:07 | 只看该作者
本帖最后由 singleywy 于 2011-3-15 09:08 编辑

12# 刘前辈
我给出了这样的程序,使用了信号量查询语句,不知如何:
#include<reg52.h>
#include "Os_api.h"
#include"IOfor52.h"
void OsTimerISR()interrupt 1
{
OsIntEnter();
#if T0_TIMER_EN
ACC=((65536+8-SYS_CLK)%256);
TR0=0;
TL0+=ACC;
ACC=0;
CY=ACC&0x80;
ACC =((65536+8-SYS_CLK)/256)+ACC;
TH0+=ACC;
TR0=1; //时间管理
#endif
#if T2_TIMER_EN
#endif
#if TIME_EXPAND_EN
    OsRunTime--;
if(OsRunTime == 0){
  OsRunTime=TIME_COEFFICIENT-1;
  OsTimeTick();
}
#else
    OsTimeTick();
#endif
OsIntExit();   
}
void TaskA()
{
while(1)
{
  if( OsSemQuery(4) & OsSemQuery(0) & SEM_USEFUL){
   OsSemP(4,0);
   OsSemP(0,0);
   LED1_ON;
   OsTaskWait(DO_TMO,200);
   LED1_OFF;
   OsSemV(0);//释放信号量0
   OsSemV(4);//释放信号量4
  }
  OsTaskWait(DO_TMO,200);
}
}

void TaskB()
{
   while(1)
   {
  if( OsSemQuery(0) & OsSemQuery(1) & SEM_USEFUL){
   OsSemP(0,0);
   OsSemP(1,0);
   LED2_ON;
   OsTaskWait(DO_TMO,200);
   LED2_OFF;
   OsSemV(1);//释放信号量1
   OsSemV(0);//释放信号量0  }
  OsTaskWait(DO_TMO,200);
   }
}
void TaskC()
{
while(1)
{
  if( OsSemQuery(1) & OsSemQuery(2) & SEM_USEFUL){
   OsSemP(1,0);
   OsSemP(2,0);
   LED3_ON;
   OsTaskWait(DO_TMO,200);
   LED3_OFF;
   OsSemV(2);//释放信号量2
   OsSemV(1);//释放信号量1
  }
  OsTaskWait(DO_TMO,200);
}
}
void TaskD()
{
while(1)
{
  if( OsSemQuery(2) & OsSemQuery(3) & SEM_USEFUL){
   OsSemP(2,0);
   OsSemP(3,0);
   LED4_ON;
   OsTaskWait(DO_TMO,200);
   LED4_OFF;
   OsSemV(3);//释放信号量3
   OsSemV(2);//释放信号量2
  }
  OsTaskWait(DO_TMO,200);
}
}
void TaskE()
{
while(1)
{
  if( OsSemQuery(3) & OsSemQuery(4) & SEM_USEFUL){
   OsSemP(3,0);
   OsSemP(4,0);
   LED5_ON;
   OsTaskWait(DO_TMO,200);
   LED5_OFF;
   OsSemV(4);//释放信号量4
   OsSemV(3);//释放信号量3
  }
  OsTaskWait(DO_TMO,200);
}
}
void TaskIdle()
{
  static uint8 i;
  LED0_ON;
  OsSemCreate(0,1);//创建信号量0,初始值为1;
  OsSemCreate(1,1);//创建信号量1,初始值为1;
  OsSemCreate(2,1);//创建信号量2,初始值为1;
  OsSemCreate(3,1);//创建信号量3,初始值为1;
  OsSemCreate(4,1);//创建信号量4,初始值为1;
  while(1)
  {
   i++;
  LED0=LED0^1;
  }
}
void main()
{
OsTaskCreate(0,(uint16)TaskA);
OsTaskCreate(1,(uint16)TaskB);
OsTaskCreate(2,(uint16)TaskC);
OsTaskCreate(3,(uint16)TaskD);
OsTaskCreate(4,(uint16)TaskE);
OsTaskStart(5,(uint16)TaskIdle);
}

使用特权

评论回复
17
singleywy|  楼主 | 2011-3-15 09:19 | 只看该作者
10# 刘前辈
首先,感谢刘前辈的指教,是我在解题上犯了轻率武断的错误,同时并没有对您的评论作认真的审读而是主观臆断地认为您不理解我的算法;
当我回头仔细阅读您发的每一个贴子,其实问题已经指出来了,而那时的我依旧执迷不悟,感觉自己是多么的愚蠢了!
我写OsSemQuery()查询语句,也并不是为解此题而设计的,其实只用OsSemP,OsSemV也可以做好,只是系统运行花费的时间增加了,不如查询来的方便,况且,查询函数在其他的RTOS中也是有的,只是我想当然地认为不需要,便去除了,现在才发现,其实它真的很重要,尤其是处理死锁,多个资源获取问题;

使用特权

评论回复
18
qrshi| | 2011-3-15 13:03 | 只看该作者
有意思,做个标记,以后详细看。

使用特权

评论回复
19
刘前辈| | 2011-3-15 16:20 | 只看该作者
本帖最后由 刘前辈 于 2011-3-15 16:26 编辑

还是死锁呀?为什么?并发概念又讲一遍:
5个哲学家优先级平等!5个人都一样!那么凭什么A号哲学家就能先拿到第二只筷子?——当A拿到第一只筷子的时候,B、C、D、E 也同样拿到了第一只筷子。5个人不是对等吗?凭什么你A/B/C/D/E就能优先拿到第二只筷子?
第一条语句 :
if( OsSemQuery(4) & OsSemQuery(0) & SEM_USEFUL)

有问题吗?——在一个多任务并发程序中,如果这条语句不被保护,那么它的测试结果是不确定的!(除非你OsSemQuery(4) 和 OsSemQuery(0)是私有变量)否则这里刚测试完,还没有开始运行下一条 OsSemP(4,0);那边哲学家E已经率先执行 OsSemP(4,0); ——结果就全乱了。如果总从裸奔角度去安排5个哲学家谁先谁后。还用OS多任务并发干什么?

另一点:A拿到第一支筷子,和其他4个人拿到第一只筷子都是对等编程,没有说“理论上肯定有一个人先……”  死锁本来就是低概率事件。5个人都拿到第一支筷子,只要有一个人性格谦让一点,修养好一点,让出一只筷子,死锁就打破了。——谁让出来?我凭什么让?谁让出来就不对等了。
要是谁说,“这在单处理器上不可能出现,”那就把并发理解为5个处理器同时并行运行吧。记得某版主说过,也是教材上讲的:OS 就是为每个用户任务提供一台虚拟处理器。——管什么单处理器还是多处理器,概念一样。5个哲学家5台虚拟处理器,同时、对等、宏观并行运行。没谁有优先级和别人不一样。

void TaskA()
{
while(1)
{
  if( OsSemQuery(4) & OsSemQuery(0) & SEM_USEFUL){
   OsSemP(4,0);
   OsSemP(0,0);
   LED1_ON;
   OsTaskWait(DO_TMO,200);
   LED1_OFF;
   OsSemV(0);//释放信号量0
   OsSemV(4);//释放信号量4
  }


使用特权

评论回复
20
singleywy|  楼主 | 2011-3-15 17:57 | 只看该作者
17# 刘前辈
确切的说,写的程序的确存在问题,在申请两个信号量的时候,应该用临界区来保护;
不过,解决五个哲学家吃饭问题,并非只有一解:
您说无论什么时候,只有哲学家发现他不具备吃饭的条件,就什么也不做,(这只是其中一解)
然而哲学家问题实质上就是只有不发生死锁即可,即保证五个哲学家在有限的时间内完成吃饭动作,而不是无限的等待;
然而系统中处理这个问题也是这样的么?当一个任务获取多个资源时,要么都获取,要么一个也不获取?您所举的解法,只是其一,事实上的操作系统的解法很多:

0)先得到全部资源再进行下一步工作,否则不获取;
1)用同样的顺序获取多个资源,释放时以相反的顺序释放资源;
2)使用超时等待资源,如果在一定时间内,无法获取资源,释放拥有的资源;
。。。

所以说,我先前的做法是方法1

使用特权

评论回复
21
singleywy|  楼主 | 2011-3-15 18:21 | 只看该作者
还是死锁呀?为什么?并发概念又讲一遍:
5个哲学家优先级平等!5个人都一样!那么凭什么A号哲学家就能先拿到第二只筷子?——当A拿到第一只筷子的时候,B、C、D、E 也同样拿到了第一只筷子。5个人不是对等吗?凭什 ...要是谁说,“这在单处理器上不可能出现,”那就把并发理解为5个处理器同时并行运行吧。记得某版主说过,也是教材上讲的:OS 就是为每个用户任务提供一台虚拟处理器。——管什么单处理器还是多处理器,概念一样。5个哲学家5台虚拟处理器,同时、对等、宏观并行运行。没谁有优先级和别人不一样。
刘前辈 发表于 2011-3-15 16:20

采用优先级抢占式系统,来解决这个哲学问题,显然不合适,但正由于信号量作用,导致每个任务不管等级高低,都必须等待拥有资源的任务放弃资源才行,这一点对于优先级抢占式系统来说,实际上已经是优先级翻转了,即每个任务在使用信号量是平等的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

295

帖子

3

粉丝