才半页

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  • 李微微
  • 201821121001
  • 计算1811

1. 选择哪一个问题

  • 哲学家进餐问题
  • 有五个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。
    约束条件:
    (1)只有拿到两只筷子时,哲学家才能吃饭。
    (2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。
    (3)任一哲学家在自己未拿到两只筷子吃完饭前,不会放下手中已经拿到的筷子。

2. 给出伪代码

伪代码如下:

semaphore chopstick[5];           //五种信号量
semaphore m = 4//最多四个哲学家同时拿起左筷
while(wait(num_mutex))
{
    wait(chopstick[i]);           //拿起左筷
    wait(chopstick[(i+1)%5]);     //拿起右筷
    
    sem_post(chopstick[i]);        //放下左筷
    sem_post(m);
    sem_post(chopstick[(i+1)%5]);  //放下右筷
}

算法思想:至多允许有四位哲学家同时去拿左边的筷子,然后再允许拿右边的筷子。最终保证至少有一位哲学家能够进餐,并在用毕时能同时释放他用过的两只筷子,从而使更多的哲学家能够进餐。

3. 给出完整代码

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <malloc.h>
  4 #include <time.h>
  5 #include <unistd.h>
  6 #include <pthread.h>
  7 #include <semaphore.h>
  8
  9 #define N 5
 10
 11 sem_t chopsticks[N];            //设置5种信号量,有5种不同类型的资源
 12 sem_t m;                        //最多允许4个哲学家同时拿起左筷子
 13
 14 int philosophers[N] = {0, 1, 2, 3, 4};//代表5个哲学家的编号
 15 void delay (int len) {
 16     int i = rand() % len;
 17     int x;
 18     while (i > 0) {
 19         x = rand() % len;
 20         while (x > 0) {
 21             x--;
 22         }
 23         i--;
 24     }
 25 }
 26 void *philosopher (void* arg) {
 27     int i = *(int *)arg;
 28     int left = i;               //左筷编号和哲学家编号相同
 29     int right = (i + 1) % N;    //右筷编号为哲学家编号+1
 30     while (1) {
 31         printf("哲学家%d正在思考问题\n", i);
 32         delay(60000);
 33         printf("哲学家%d饿了\n", i);
 34         sem_wait(&m);            /*若前4个哲学家同时拿起左筷,第五个不能同时拿起左筷,保证至少有一位哲学家能吃到饭,解决死锁*/
 35         sem_wait(&chopsticks[left]);    //此时这个哲学左筷子的信号量-1后>=0,表示能继续执行
 36
 37         printf("哲学家%d拿起了%d号筷子,现在只有一支筷子,不能进餐\n", i, left);
 38         sem_wait(&chopsticks[right]);
 39         printf("哲学家%d拿起了%d号筷子, 现在有两支筷子,开始进餐\n", i, right);
 40         delay(60000);
 41         sem_post(&chopsticks[left]);
 42         printf("哲学家%d放下了%d号筷子\n", i, left);
 43         sem_post(&m);                  //当哲学家释放了左筷子时,信号量m+1
 44         sem_post(&chopsticks[right]);
 45         printf("哲学家%d放下了%d号筷子\n", i, right);
 46     }
 47 }
 48
 49 int main (int argc, char **argv) {
 50     srand(time(NULL));
 51     pthread_t philo[N];
 52     //信号量初始化
 53     for (int i=0; i<N; i++) {
 54         sem_init(&chopsticks[i], 0, 1);
 55     }
 56     sem_init(&m, 0, 4);
 57     //创建线程
 58     for (int i=0; i<N; i++) {
 59         pthread_create(&philo[i], NULL, philosopher, &philosophers[i]);
 60     }
 61     //挂起线程
 62     for (int i=0; i<N; i++) {
 63         pthread_join(philo[i], NULL);
 64     }
 65     //销毁信号量
 66     for (int i=0; i<N; i++) {
 67         sem_destroy(&chopsticks[i]);
 68     }
 69     sem_destroy(&m);
 70     return 0;
 71 }

4. 运行结果并解释

运行结果:

解释:刚开始所有哲学家(编号0-4)都在思考,无人拿起筷子。随后,因为大家都在思考,所以哲学家1能够拿起两只筷子,同理哲学家4也能够拿着两只筷子。接着哲学家1放下两只筷子,哲学家3因为哲学家4拿走的筷子而只能拿着一只筷子,因而哲学家2和哲学家1只能分别有哲学家1放下的一只筷子……程序不断输出,不存在死锁状态。

5. 加分项

上述解决哲学家进餐问题,解决潜在死锁问题的原理是:最多允许4个哲学家同时拿起左筷,若前4个哲学家同时拿起左筷,第五个不能同时拿起左筷,保证至少有一位哲学家能吃到饭,吃完后放下筷子,以便更多人食用,解决死锁。

6. 遇到的问题

       问题:编译代码时报错:undefined reference to sem_init sem_wait.......

       解决:因为pthread并非Linux系统的默认库,编译时注意加上-lpthread参数,以调用链接库。

      参考链接:https://blog.csdn.net/weixin_39531549/article/details/100857716

posted on 2020-05-29 23:24  才半页  阅读(238)  评论(0编辑  收藏  举报