哲学家就餐问题

哲学家就餐问题是经典的死锁问题

什么是死锁?

多个进程或线程相互等待对方的资源,在等到对方资源之前,也不会释放自己的资源,这样造成循环等待的现象,若无外力作用,他们都无法推进下去,这样就产生了死锁。

死锁产生的必要条件:

  • 互斥性
  • 请求并保持
  • 不可剥夺
  • 循环等待

防止死锁的办法:

  • 一次性分够(破坏请求并保持的条件)
  • 资源可剥夺(破坏不可剥夺条件)
  • 资源有序分配(破坏循环等待条件)

这几种方法只是理论上的,基本不可能实现

我们只能尽量的避免死锁
经典的死锁避免算法:银行家算法

银行家算法了解一下:(四句话)

  1. 当顾客的资金需求少于银行家现有的资金总量时,接纳该顾客
  2. 顾客可以分期贷款,但贷款总量不能超过最大需求量
  3. 当银行家现有资金不能满足顾客需求时,可延迟交付,但总能在有限时间内让顾客得到贷款
  4. 当顾客使用完全部资金后,一定要在有限时间内gui归还全部资金。

下来我们具体看一下哲学家就餐问题如何解决:
这里写图片描述

为了不产生死锁,我们必须保证拿左筷子和拿右筷子这两步是一个原子操作,此时我们就可以借助信号量来实现,因为semop()这个函数具有原子性。

具体步骤如下:
1.信号量集中设置5个信号量
2.都设置初值为1(表示5个筷子的资源可用数)
3.除父进程外再创建4个子进程,每个进程代表一个哲学家
4.每个进程都先申请自己需要的两个筷子的资源(P操作)
5.使用结束后释放(V操作)
代码实现:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>

union semun
{
  int val;
};

int semid;

//P操作
void get2kz(int no)
{
  struct sembuf sb[2]={
    {no,-1,0},
    {(no+1)%5,-1,0}
  };
  semop(semid,sb,2);
}
//V操作
void put2kz(int no)
{
  struct sembuf sb[2]={
    {no,1,0},
    {(no+1)%5,1,0}
  };
  semop(semid,sb,2);
}

void fun(int no)
{
  while(1)
  {
    printf("%d 号哲学家正在思考...\n",no);
    sleep(rand()%3);
    get2kz(no);//请求两个筷子资源
    printf("%d 号哲学家开始就餐\n",no);
    sleep(rand()%3);
    printf("%d 号哲学家就餐完毕\n",no);
    put2kz(no);//释放两个筷子的资源

  }
}

int main()
{
  srand(getpid());

  //创建一个信号量集,包含五个信号量,代表5个筷子的资源
  semid=semget(ftok(".",1),5,IPC_CREAT|0644);
  if(semid<0)
  {
    perror("semget");
    exit(1);
  }

  int i=0;
  //为信号量集中的每个信号量赋初值1
  union semun su={1};
  for(i=0;i<5;i++)
  {
    semctl(semid,i,SETVAL,su);
  }

  //创建四个子进程,代表每个哲学家
  int no=0;
  for(i=1;i<5;i++)
  {
    if(fork()==0)//子进程
    {
      no=i;
      break;
    }
  }
  fun(no);
  return 0;
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值