美文网首页
【专项专攻】01-哲学家进餐问题

【专项专攻】01-哲学家进餐问题

作者: 创造new_world | 来源:发表于2019-06-17 18:14 被阅读0次

    前言:

    image.png

    当一位哲学家思考时,他与其他同事不交流。时而,他会感到饥饿,并试图拿起与他相近的两根筷子(筷子在他和他的左或右邻居之间)。一个哲学家一次只能拿起一根筷子。显然,他不能从其他哲学家手里拿走筷子。当一个饥饿的哲学家同时拥有两根筷子时,他就能吃。在吃完后,他会放下两根筷子,并开始思考。

    哲学家就餐问题是一个经典的同步问题,这不是因为其本身的实际重要性,也不是因为计算机科学家不喜欢哲学家,而是因为它是大量并发控制问题的一个例子。这个代表型的例子满足:在多个进程之间分配多个资源,而且不会出现死锁和饥饿。

    哲学家进餐问题:
    (一)问题:
    5个哲学家围坐在一个圆桌上,每两个哲学家之间都有一只筷子,哲学家平时进行思考,只有当他们饥饿时,才拿起筷子吃饭。
    规定每个哲学家只能先取其左边筷子,然后取其右边筷子,然后才可以吃饭。

    (二)分析:
    每一只筷子都是一个临界资源,设置5个互斥信号量。
    Semaphore stcik[5]={1,1,1,1,1}

    因为:只有占有左边筷子-》占有右边筷子-》吃饭
    所以p(左边筷子)-》p(右边筷子)-》吃饭

    (三)实现:
    main(){
    philosopher(0);//注意不可以用循环,因为此中是4个并列的进程。
    philosopher(1);
    philosopher(2);
    philosopher(3);
    philosopher(4);
    }

    philosopher(int i){
    while(1){
    思考;
    p(stick[i]);//取左边筷子
    p(stick[i+1]);//取右边筷子

    进餐;
    V(stick[i]);
    v(stick[i+1]);
    }
    }

    (四)问题:
    如果5个哲学家同时拿起自己左边的筷子,就会发生死锁。

    (五)防止死锁的方法:

    (1)方法一:
    规定在拿到左侧的筷子后,先检查右面的筷子是否可用。如果不可用,则先放下左侧筷子, 等一段时间再重复整个过程。

    问题:发生饥饿现象;
    如果同时拿起左边筷子,则右边的筷子都不可用,则放下,然后再次拿起,。。。,则谁都无法就餐,

    (2)方法二:
    最多允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最终总会释
    放出他所使用过的两支筷子,从而可使更多的哲学家进餐。

    伪码:
    semaphore chopstick[5]={1,1,1,1,1};
    semaphore room=4;
    void philosopher(int i)
    {
    while(true)
    {
    think();
    wait(room); //请求进入房间进餐
    wait(chopstick[i]); //请求左手边的筷子
    wait(chopstick[(i+1)%5]); //请求右手边的筷子
    eat();
    signal(chopstick[(i+1)%5]); //释放右手边的筷子
    signal(chopstick[i]); //释放左手边的筷子
    signal(room); //退出房间释放信号量room
    }
    }

    (3)将拿左筷子,与拿右筷子当做一个原子操作:(即只有当左右筷子均可以拿到时,才拿筷子。)

    方法一:
    利用AND 型信号量机制实现:根据课程讲述,在一个原语中,将一段代码同时需
    要的多个临界资源,要么全部分配给它,要么一个都不分配,因此不会出现死锁的情形。

    伪码:
    semaphore chopstick[5]={1,1,1,1,1};
    void philosopher(int I)
    {
    while(true)
    {
    think();
    P(chopstick[(I+1)]%5,chopstick[I]);
    eat();
    V(chopstick[(I+1)]%5,chopstick[I]);
    }
    }

    方法二:
    利用信号量的保护机制实现。通过信号量mutex对eat()之前的取左侧和右侧筷
    子的操作进行保护,使之成为一个原子操作,这样可以防止死锁的出现。

    伪码:
    semaphore mutex = 1 ;
    semaphore chopstick[5]={1,1,1,1,1};
    void philosopher(int I)
    {
    while(true)
    {
    think();
    P(mutex);
    P(chopstick[(I+1)]%5);
    P(chopstick[I]);
    V(mutex);

    eat();
    V(chopstick[(I+1)]%5);
    V(chopstick[I]);
    }
    }

    (4)规定奇数号的哲学家先拿起他左边的筷子,然后再去拿他右边的筷子;而偶数号 的哲学家则相反。
    伪码:
    semaphore chopstick[5]={1,1,1,1,1};
    void philosopher(int i)
    {
    while(true)
    {
    think();
    if(i%2 == 0) //偶数哲学家,先右后左。
    {
    P (chopstick[ i + 1 ] mod 5) ;
    P (chopstick[ i]) ;
    eat();
    V (chopstick[ i + 1 ] mod 5) ;
    V (chopstick[ i]) ;
    }
    Else //奇数哲学家,先左后右。
    {
    p (chopstick[ i]) ;
    p (chopstick[ i + 1 ] mod 5) ;
    eat();
    V (chopstick[ i]) ;
    V (chopstick[ i + 1 ] mod 5) ;
    }
    }

    相关文章

      网友评论

          本文标题:【专项专攻】01-哲学家进餐问题

          本文链接:https://www.haomeiwen.com/subject/irjzfctx.html