以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 计算机考研交流 』   (http://bbs.xml.org.cn/list.asp?boardid=67)
----  北大必考题,PV操作中的疑惑。。。  (http://bbs.xml.org.cn/dispbbs.asp?boardid=67&rootid=&id=38190)


--  作者:borlong
--  发布时间:9/22/2006 12:41:00 PM

--  北大必考题,PV操作中的疑惑。。。
对设置同步信号量,那位牛人能给点经验啊!
题:某系统如此定义p,v操作:
    p(s)
         s=s-1;
         若s<0,本进程进入s信号量等待队列的末尾;否则,继续执行。
   v(s)
        s=s+1;
        若s>=0,释放等待队列中末尾的进程,否则,继续执行。
现有4个进程p1,p2,p3,p4竞争使用某一个互斥资源(每个进程可能反复使用多次),试用上面的定义的p,v操作正确解决p1,p2,p3,p4对该互斥资源的使用问题。
--  作者:Supremgoooo
--  发布时间:9/22/2006 11:11:00 PM

--  
恩这个定义有问题。你的疑惑是啥?
--  作者:apolor
--  发布时间:9/23/2006 7:24:00 AM

--  
以下是引用Supremgoooo在2006-9-22 23:11:00的发言:
恩这个定义有问题。你的疑惑是啥?


对,作者在定义v(s)时好像有问题。
   v(s)
        s=s+1;
        若s>=0,释放等待队列中末尾的进程,否则,继续执行。

其中s>=0是不是应该是s<=0,如果是这样的话,该题就成为《操作系统》教材第一版第四章的37题(P139),这道题可以用层层加锁或二叉树的方式来实现互斥。且二叉树的方式效率较高。
--  作者:borlong
--  发布时间:9/23/2006 7:15:00 PM

--  
不好意思。。。我太粗心了!
因为我对pv操作很是模糊,就是说小弟我对pv程序设计没有信心啊!
上述的的确应该更正!!!!!!! 谢谢啦!
     v(s)
      s=s+1;
     若s<=0,释放等待队列中末尾的进程,否则继续执行。

对不起大家了。。:P

我的问题是:(a),在本题v(s)操作中,若s依然<0,那么按照定义还要释放等待队列吗?????
s<0不就是说明,已经没有可用资源了吗?那么释放进程有什么意义呢?

(b),难道这题的解法是这样的???:

    pi: (i=1or2or3or4)
             while(1)
                     { p(s);
                        使用资源。
                       v(s);
                     }

难道是仅此而已,如此简单,不会吧!!!还是怎么解法呢?

希望牛人能给点建议,小弟不胜感激啊!
但愿我的问题没有让您感到可爱。。。:p


--  作者:yangling_1985
--  发布时间:9/23/2006 10:56:00 PM

--  
当信号量s>0可以理解为可用资源数为s ;当s<0时,说明此时等待队列中有|s|个进程。
一个进程结束时,会释放它所占用的一个资源。
此时,
若s<0(即s+1<=0),则说明等待队列中有|s|个进程在等待,于是从取队列中第一个进程,并将释放的资源分配给这个进程;
反之,若s>=0,则表明无进程在等待资源,即所有进程均获得所需资源。故什么都不用做。
不知道我说明白了没有。
ps:很久没看操作系统了,感觉那个题目的解法没有大问题。
请大家指教。

--  作者:Supremgoooo
--  发布时间:9/23/2006 11:04:00 PM

--  
(a)要。你要明白s<0的意义,表示有|s|+1个进程被阻塞,所以需要唤醒其中的一个。

(b)可以。但是这样会出现先到进程的饥饿(STARVATION),算法不合理。本题有两种比较好的解法:漏斗法和倒二叉树法,前者比较难理解,我介绍一下后者:

思想:因为这个定义对两个互斥进程是没问题的,所以把4个互斥进称变成两两互斥。即将4个进程分成两组,然后引入两个虚资源,每组进程为了争夺互斥资源,必须先得到虚资源。

semaphore s;       //初值为1
semaphore vs1;    //初值为1
semaphore vs2;    //初值为1

void Proc_P1_P2()
{
L:   P(vs1);
     P(s);
     Do sth...
     V(s);
     V(vs1);
     goto L;
}

void Proc_P3_P4()
{
L:   P(vs2);
     P(s);
     Do sth...
     V(s);
     V(vs2);
     goto L;
}


--  作者:yangling_1985
--  发布时间:9/23/2006 11:41:00 PM

--  
以下是引用Supremgoooo在2006-9-23 23:04:00的发言:
(a)要。你要明白s<0的意义,表示有|s|+1个进程被阻塞,所以需要唤醒其中的一个。


我觉得当s<0时应该是表示有|s|个进程阻塞吧。
设初始状态是所有已申请资源的进程都获得资源且所有资源均已分配(S初值为0),N为阻塞的进程数(初值为0)
每当有一个新的进程申请资源时(P(S)) ,S=S-1,且进入阻塞队列。同时N=N+1.
当有一进程运行结束,则(v(s)) s=s+1.同时 从等待队列中取出一个进程。N=N-1
设次过程中始终有等待进程,则可得出N=|S|。

SUPREMGOOOO兄中的S是不是指在V(S)中以自加一次的S?


--  作者:carroty
--  发布时间:9/24/2006 10:49:00 AM

--  
to Supremgoooo:

是不是还会早成同一组里的早到进程的饥饿呢?

比如两个队列:

vs1:2,3,4,5,....
vs2:12,13,14,15.....
s:11
runing :1
代号代表到达的先后顺序.

为什么不是每个类型的进程自己一个队列呢?
这样似乎等待的队列还会更短一些.


其实,我不知道这个题到底要考察什么?


--  作者:apolor
--  发布时间:9/24/2006 3:23:00 PM

--  
以下是引用Supremgoooo在2006-9-23 23:04:00的发言:
(b)可以。但是这样会出现先到进程的饥饿(STARVATION),算法不合理。本题有两种比较好的解法:漏斗法和倒二叉树法,前者比较难理解,我介绍一下后者:

思想:因为这个定义对两个互斥进程是没问题的,所以把4个互斥进称变成两两互斥。即将4个进程分成两组,然后引入两个虚资源,每组进程为了争夺互斥资源,必须先得到虚资源。

semaphore s;       //初值为1
semaphore vs1;    //初值为1
semaphore vs2;    //初值为1

void Proc_P1_P2()
{
L:   P(vs1);
      P(s);
      Do sth...
      V(s);
      V(vs1);
      goto L;
}

void Proc_P3_P4()
{
L:   P(vs2);
      P(s);
      Do sth...
      V(s);
      V(vs2);
      goto L;
}



利用倒立二叉树来实现互斥,效率较高。虽然不会发生饥饿,但有个小问题:如果进程申请使用资源的次序为P1、P2、P3、P4,而实际使用临界资源的次序可能为:P1、P3、P2、P4。

下面介绍一个层层加锁的方式实现的互斥,就当拓展一下思路吧。该实现效率很低,每层只锁住一个进程。
semaphore mutex1=1;
semaphore mutex2=2;
semaphore mutex3=3;

Proc(i){
    while(true){
          P(mutex3);
          P(mutex2);
          P(mutex1);
              do sth...
          V(mutex1);
          V(mutex2);
          V(mutex3);
    }
}

另外,Supremgoooo能否把提到的“漏斗法”实现贴上来,开阔一下眼界:)


--  作者:borlong
--  发布时间:9/24/2006 10:04:00 PM

--  
小弟在此谢过大家了。

Brother  supremgoooo :您说,可以。但是这样会出现先到进程的饥饿(STARVATION),算法不合理。本题有两种比较好的解法:漏斗法和倒二叉树法。

您能否解释下,饥饿的过程呢? 就是简要说明一下,如何饥饿的。
因为小弟正在努力尝试着去想象 pv操作过程。这个不像一般的程序设计,还要考虑“次序”问题。我对这方面甚是迷惑!

您能否将“漏斗法”也贴出来呢?让我仔细思考一下其中的奥妙呢。
您的os书本是什么教材啊?怎么这么丰富呢?北大的os上没有你说的方法啊!
麻烦您了啊! 谢谢啦! :P

在此感谢大家对小弟的关心和帮助!


--  作者:Supremgoooo
--  发布时间:9/24/2006 11:48:00 PM

--  
首先回答yangling_1985的疑惑,让我们再看这个定义:

v(s)  //此时s表示等待进程的个数,即有|s|个等待进程
s=s+1;
若s<=0,释放等待队列中末尾的进程,否则,继续执行。//因为s加了1,所以此时有|s|+1个等待进程。

下面是carroty的问题:
本题考察队P,V定义的理解,P,V原本的意思唤醒上是随机的,即从所有的等待进程中随机的唤醒一个进程,这也体现了多道程序设计的不确定性,不可在现性。而本题说从末尾唤醒,首先它违背了P,V随机性这个特征,其次,每个进程是在不断的反复执行这个操所的,假设某一时刻P3在临界区内,P1,P2都P了而被阻塞,这时P4也P一下,P3执行完后,V一下,则P4进临界区,同时P3又P,之后P3又进。。。于是,P1,P2就永远的等待下去,此所谓饥饿。

一个进程就一个程序,在执行时无所谓队列。为什么要排队呢?就是因为有多个进程对一个资源进行抢夺,例如:你去食堂打饭,就你一个人,你需要排队吗?但是人很多的话,总是站在你后面的人先打饭,而你后面的人源源不断的补上来,那你不是要一直等下去?

下面回答borlong的问题:
饥饿就是一个进程因为长时间的得不到资源满足而一直等下去,它往往反映出算法的不合理。

漏斗思想是用队列来实现这个过程,就是把进程对资源的请求排队,首先要占到队尾,然后向前移动一位。。。直道站到队首。实现方法是队尾可以允许站4个人,就是信号量初值4,然后向前是3。。。1。算法你自己写吧。


--  作者:borlong
--  发布时间:9/25/2006 7:49:00 AM

--  
小弟在此激情感谢大家!

Dear Brothers, 您们让小弟见识不少啊!在此请教了!

pv程序设计出来以后,有什么特别的方法来测试正确与否吗?能够用一些简单的步骤来
判断出我的程序有无死锁或者饥饿等等之类的呢?
难道非一定要用列举法,分别一个一个的试探着进行吗?

我的pv思路越来越明了了! 感谢大家!


--  作者:shenfuquan
--  发布时间:9/25/2006 2:50:00 PM

--  
v(s)  //此时s表示等待进程的个数,即有|s|个等待进程
-------------------这是对的
s=s+1;
若s<=0,释放等待队列中末尾的进程,否则,继续执行。
------------------这时因为s信号量对应对列若有进程等待,此时s必为负值(s<0),之后因为s加了1,所以应该为|s|-1个等待进程。

以下是引用Supremgoooo在2006-9-24 23:48:00的发言:
首先回答yangling_1985的疑惑,让我们再看这个定义:

v(s)  //此时s表示等待进程的个数,即有|s|个等待进程
s=s+1;
若s<=0,释放等待队列中末尾的进程,否则,继续执行。//因为s加了1,所以此时有|s|+1个等待进程。

下面是carroty的问题:
本题考察队P,V定义的理解,P,V原本的意思唤醒上是随机的,即从所有的等待进程中随机的唤醒一个进程,这也体现了多道程序设计的不确定性,不可在现性。而本题说从末尾唤醒,首先它违背了P,V随机性这个特征,其次,每个进程是在不断的反复执行这个操所的,假设某一时刻P3在临界区内,P1,P2都P了而被阻塞,这时P4也P一下,P3执行完后,V一下,则P4进临界区,同时P3又P,之后P3又进。。。于是,P1,P2就永远的等待下去,此所谓饥饿。

一个进程就一个程序,在执行时无所谓队列。为什么要排队呢?就是因为有多个进程对一个资源进行抢夺,例如:你去食堂打饭,就你一个人,你需要排队吗?但是人很多的话,总是站在你后面的人先打饭,而你后面的人源源不断的补上来,那你不是要一直等下去?

下面回答borlong的问题:
饥饿就是一个进程因为长时间的得不到资源满足而一直等下去,它往往反映出算法的不合理。

漏斗思想是用队列来实现这个过程,就是把进程对资源的请求排队,首先要占到队尾,然后向前移动一位。。。直道站到队首。实现方法是队尾可以允许站4个人,就是信号量初值4,然后向前是3。。。1。算法你自己写吧。



--  作者:borlong
--  发布时间:9/25/2006 5:13:00 PM

--  
Dear Supremgoooo says,There is a starvation in
my coprogame!!! but!!!
我。。我。。我。。我看不出我解法里面的饥饿啊!!!

我的解法:
pi: (i=1or2or3or4)
             while(1)
                     { p(s);
                        使用资源。
                       v(s);
                     }

换成语言描述是:任意进程pi来执行,先是执行p(s),如果通过,则使用,否则等待啊!!!
这个程序有问题吗???  我不明白!!!
难道是〉=2个进程同时来执行时候会出现问题吗?
那么后果是怎样???  这个地方,我是无法用思维去想象!!!

还请牛人来解释。。。  :P 急切的期待!!!!!!


--  作者:shenfuquan
--  发布时间:9/26/2006 10:31:00 AM

--  
如果进程申请互斥资源的顺序如下:P1,P2,P3,P4,P1,P2,P3,P4,P1......
在P1进行V操作时,又有一个新的P1进程申请互斥资源而等待,而题目V的操作释放队列末尾的进程,所以P1进行V操作时,它释放的是新的P1进程,重复以上操作, 只有P1类进程才申请到互斥资源,(P2,P3,P3)类进程只会starvation(饥饿)。
以下是引用borlong在2006-9-25 17:13:00的发言:
Dear Supremgoooo says,There is a starvation in
my coprogame!!! but!!!
我。。我。。我。。我看不出我解法里面的饥饿啊!!!

我的解法:
pi: (i=1or2or3or4)
              while(1)
                      { p(s);
                         使用资源。
                        v(s);
                      }

换成语言描述是:任意进程pi来执行,先是执行p(s),如果通过,则使用,否则等待啊!!!
这个程序有问题吗???  我不明白!!!
难道是〉=2个进程同时来执行时候会出现问题吗?
那么后果是怎样???  这个地方,我是无法用思维去想象!!!

还请牛人来解释。。。  :P 急切的期待!!!!!!



--  作者:mxf3306
--  发布时间:9/26/2006 6:33:00 PM

--  
Supremgoooo兄,这倒二叉树和漏斗法不知你是从哪看来的,让人耳目一新,我翻了很多教材都没找到出处,相关东西似乎只在北大的讲义上有所提及。能否提供一下资料来源。
--  作者:borlong
--  发布时间:9/26/2006 9:01:00 PM

--  
dear shenfuquan, 我懂了! 这个饥饿跟v(s)定义有关系。因为从末尾处释放!
所以,有可能总会被同一个进程使用!!那么其他进程会饥饿。对不???

您有设计的方案吗?可否指点一二,:P

===========================================
对了!各位高手!

小弟我面临的最大的问题是:
当我看到一个pv程序或者别人或我写的程序。我无法用思维去模拟
该pv程序的执行!也就是无法去判断其是否正确,即不存在死锁、
饥饿等等。跟一般的程序大大的不同阿!!!
请问:能否有什么方法去判断呢?还是需要思维去模拟执行吗???
还是用图示等等方法去模拟。。。

请牛人给小弟解答!!! 急切期待。。。: P

我也期待dear Supremgoooo,将 倒二叉树和漏斗法 贴出来!!
或者说明是哪个版本上的,小弟我也没有看到啊!!!: P


--  作者:borlong
--  发布时间:9/27/2006 8:41:00 AM

--  
怎样去检测pv程序的正确与否啊?
怎样在大脑里模拟去执行呢?

因为小弟正在努力尝试着去想象 pv操作过程。这个不像一般的程序设计,还要考虑“次序”问题。我对这方面甚是迷惑!



--  作者:borlong
--  发布时间:9/27/2006 9:07:00 AM

--  利用倒立二叉树来实现互斥,效率较高。恩。。不是太明白???
您所说的效率较高,或者 能够迅速判定 该pv程序的正确与否,如没有死锁、没有饥饿,到底是怎么去判断的啊?
就拿前面几位牛人的pv解法吧,你们是如何看出没有死锁或者饥饿的呢???
有什么妙的 方法去解释呢?
能否有种方法如一般程序设计那样,可以在头脑中,稿纸上进行模拟执行呢???

小弟急切的希望牛人指点一二。
小弟让你们见笑了吧?
呵呵。。。对pv操作跟我的离散图论部分有些类似,总是无法彻底的把握!!!
小弟再次向各位高手请教了!!!!


--  作者:Supremgoooo
--  发布时间:9/29/2006 10:45:00 PM

--  
以下是引用shenfuquan在2006-9-25 14:50:00的发言:
v(s)  //此时s表示等待进程的个数,即有|s|个等待进程
-------------------这是对的
  s=s+1;
  若s<=0,释放等待队列中末尾的进程,否则,继续执行。
------------------这时因为s信号量对应对列若有进程等待,此时s必为负值(s<0),之后因为s加了1,所以应该为|s|-1个等待进程。
//这个定义没有说s必为负值;从实际的角度出发,s也是可以不为负的。
//你的意思是说s为0时有-1个进程在等待。



--  作者:wf1136
--  发布时间:9/8/2007 7:05:00 PM

--  
以下是引用Supremgoooo在2006-9-29 22:45:00的发言:
[quote]以下是引用shenfuquan在2006-9-25 14:50:00的发言:
v(s)  //此时s表示等待进程的个数,即有|s|个等待进程
  -------------------这是对的
   s=s+1;
   若s<=0,释放等待队列中末尾的进程,否则,继续执行。
  ------------------这时因为s信号量对应对列若有进程等待,此时s必为负值(s<0),之后因为s加了1,所以应该为|s|-1个等待进程。
//这个定义没有说s必为负值;从实际的角度出发,s也是可以不为负的。
//你的意思是说s为0时有-1个进程在等待。

  

  [/quote]



我觉得应该是有|s-1|个进程在等待,即当s为0时有|0-1|=1个进程在等待
不知对不对,请各位指教。
--  作者:shun
--  发布时间:9/9/2007 11:15:00 AM

--  
supergoooo兄。你的漏斗法和倒二叉树法让人耳目一新。漏斗法我理解了。不过倒二叉树我却看不出如何防止饥饿现象。能否解释一下?
W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
140.625ms