哲学家用餐模型

分析:

为了避免死锁,做了如下规定:每个哲学家先拿自己左手边的筷子,然后再去拿右手边的筷子,如果不能同时得到两支筷子,则该哲学家放下手中已有的筷子。这种规定依然会因为振荡而产生死锁,例如:每个哲学家都同时拿上了左手边的筷子,然后都阻塞,都释放左手筷子;然后又同时去拿左手边的筷子,这样周而复始,一直进行下去,就是因为振荡而产生的死锁。解决方法:规定其中一位哲学家先拿右手边的筷子,再拿左手边的筷子即可。这样即使最坏的情况下,也至少有一位哲学家可以拿到两支筷子,而只要有一位哲学家拿到了两支筷子,就肯定不会出现死锁。

在这里筷子是临界资源,即只能被哲学家互斥访问,因此可以将筷子作为互斥量或者信号量。五支筷子应该引入五个互斥量,或者5个信号量(初始值为1)。将五个哲学家当成五个线程,其编号为i(0、1、2、3、4),互斥量或信号量编号也为0、1、2、3、4。则按照规定:i=0~3时,先拿i,再拿i+1i=4时,先拿0,再拿i。在此基础上,对于每一个线程,如果不能同时拿上两支筷子,则放弃已获得的筷子,则:第一次用lock函数,采用阻塞加锁;第二次拿筷子用trylock函数,采用非阻塞加锁,并且释放掉已经拿掉的筷子。

注意:互斥量、信号量既可以用于进程间同步,也可以用于线程间同步(一般来说,进程间同步信号量用的多一点);条件变量需要结合互斥量使用;读写锁用于线程间同步,而文件锁用于进程间同步。

下面线程版采用互斥量,进程版采用信号量

//线程版哲学家用餐模型

#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

pthread_mutex_t mutex[5];

void *tfn( void *arg )
{
        int i = (int)arg;
        int ret;
        while(1) {
            if( i<4 )
            {
                pthread_mutex_lock( &mutex[i] );
                ret = pthread_mutex_trylock( &mutex[i+1] );
                if( ret != 0)
                {
                    //printf("The %dth philosopher missed the second chopstick!\n", i+1);
                    pthread_mutex_unlock( &mutex[i] );
                }else
                {
                    printf("Very good, the %dth philosopher has a pair of chopsticks to eat food!\n", i+1);
                    sleep(5);

                    pthread_mutex_unlock( &mutex[i] );
                    pthread_mutex_unlock( &mutex[i+1] );

                    //break;
                }
            }else
            {
                pthread_mutex_lock( &mutex[0] );
                ret = pthread_mutex_trylock( &mutex[i] );
                if( ret != 0)
                {
                    //printf("The %dth philosopher missed the second chopstick!\n", i+1);
                    pthread_mutex_unlock( &mutex[0] );
                }else
                {
                    printf("Very good, the %dth philosopher has a pair of chopsticks to eat food!\n", i+1);
                    sleep(5);

                    pthread_mutex_unlock( &mutex[i] );
                    pthread_mutex_unlock( &mutex[0] );

                    //break;
                }
            }

        }

        return NULL;
}

int main( void )
{
        int i, ret;
        pthread_t phi[5];
        pthread_attr_t attr;

        ret = pthread_attr_init( &attr );
        if( ret != 0 )
        {
            fprintf(stderr,"pthread_attr_init error: %s.\n", strerror(ret));
            exit(1);
        }
        ret = pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );

        if( ret != 0 )
        {
            fprintf(stderr,"pthread_attr_detach error: %s.\n", strerror(ret));
            exit(1);
        }

        for( i=0; i<5; i++)
        {
            ret =  pthread_mutex_init( &mutex[i], NULL );
            if( ret != 0 )
            {
                fprintf(stderr,"pthread_mutex_init error: %s.\n", strerror(ret));
                exit(1);
            }
        }

        for( i=0; i<5; i++)
        {
            ret = pthread_create( &phi[i], &attr, tfn, (void *)i );
            if( ret != 0 )
            {
                fprintf(stderr,"pthread_create error: %s.\n", strerror(ret));
                exit(1);
            }
        }

        pthread_attr_destroy( &attr );

        pthread_exit( NULL );
}

[root@localhost 02_pthread_sync_test]# ./philosophy_pthrd

Very good, the 2th philosopher has a pair of chopsticks to eat food!

Very good, the 4th philosopher has a pair of chopsticks to eat food!

Very good, the 1th philosopher has a pair of chopsticks to eat food!

Very good, the 3th philosopher has a pair of chopsticks to eat food!

Very good, the 3th philosopher has a pair of chopsticks to eat food!

Very good, the 1th philosopher has a pair of chopsticks to eat food!

Very good, the 1th philosopher has a pair of chopsticks to eat food!

Very good, the 3th philosopher has a pair of chopsticks to eat food!

Very good, the 3th philosopher has a pair of chopsticks to eat food!

Very good, the 1th philosopher has a pair of chopsticks to eat food!

//进程版哲学家用餐模型

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/wait.h>

int main(void)
{
        int i;
        pid_t pid;

        sem_t *s;
        s = mmap(NULL, sizeof(sem_t)*5, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
        if (s == MAP_FAILED) {
                perror("fail to mmap");
                exit(1);
        }

        for (i = 0; i < 5; i++)
                sem_init(&s[i], 0, 1);  //信号量初值制定为1,信号量,变成了互斥锁

        for (i = 0; i < 5; i++)
                if ((pid = fork()) == 0)
                        break;

        if (i < 5) {                            //子进程
                int l, r;
                srand(time(NULL));

                if (i == 4)
                        l = 0, r = 4;
                else
                        l = i, r = i+1;
                while (1) {
                        sem_wait(&s[l]);
                        if (sem_trywait(&s[r]) == 0) {
                                printf(" %c is eating\n", 'A'+i);
                                sem_post(&s[r]);
                        }
                        sem_post(&s[l]);
                        sleep(rand() % 5);
                }
                exit(0);
        }

        for (i = 0; i < 5; i++)
                wait(NULL);

        for (i = 0; i < 5; i++)
                sem_destroy(&s[i]);

        munmap(s, sizeof(sem_t)*5);

        return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值