信号量(semaphore),互斥锁(mutex)解决哲学家死锁问题

/*
author   : youfl
func     : 哲学家吃饭问题
descript :
    哲学家吃饭死锁问题,会产生死锁的主要原因是哲学家会同时拿起左边的筷子
    同时都在等右边的筷子释放,此处可以使用信号量,控制资源数量为总资源数
    量NUM - 1,在已经有NUM - 1 的筷子被使用的情况下,就不能有人再拿左边的
    筷子了进而保证哲学家不能同时获取到左边的筷子,从而解决死锁问题。  

contact:393639665@qq.com


*/
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
//此处是自己用条件变量实现的信号量处理接口,用#include <semaphore.h>替
//代"semaphore_xx.h"即可
#include "semaphore_xx.h"

#define NUM 5
pthread_mutex_t chopsticks[NUM];

using namespace sem_xx;
sem_t semm;

const char * Philosophers[] = {"A","B","C","D","E"};

void * Philosopher(void * p){  
    int * user = new int;
    *user = *(int *)p;
    int left, right;
    left = ((*user) + 5 - 1) % NUM;
    right = ((*user) + 1) %NUM;
   
    while(1){       
        sleep(rand()%5);
        sem_wait(&semm);

        const char * name = Philosophers[(*user)];

        pthread_mutex_lock(chopsticks + left);
        printf("Philosopher %s fetches chopstick %d\n",name, left+1);
        sleep(rand()%2);
        pthread_mutex_lock(chopsticks + right);
        printf("Philosopher %s fetches chopstick %d\n",name, right+1);
        sleep(rand()%5);
        pthread_mutex_unlock(chopsticks + right);
        pthread_mutex_unlock(chopsticks + left);
        printf("Philosopher %s droped chopsticks %d %d\n",name, left+1, right+1);
        sem_post(&semm);
    }
}
int main(){
    int i = 0;
    pthread_t array[NUM];
   
    sem_init(&semm, NUM - 1);
    while(i<NUM)
        pthread_mutex_init(chopsticks + i++, NULL);
       
    for(int j = 0; j<NUM; j++){
        pthread_create(array + j, NULL, &Philosopher, &j);
        sleep(1);
    }
   
    for(int j = 0; j<NUM; j++)
        pthread_join(array[j], NULL);
    return 0;
}

 

ps: "semaphore_xx.h" 见下篇 条件变量实现的信号量处理接口

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哲学家进餐问题是一个经典的同步问题,其中多个哲学家(线程)围坐在一张圆桌上,每个哲学家需要交替地执行思考和进餐两个行为,但是他们需要共享一组资源(也就是筷子),因此需要使用同步机制来避免和饿问题。 其中,信号是一种常见的同步机制,可以通过 P 操作和 V 操作来实现进程间的同步和互斥。下面是一个利用信号机制解决哲学家进餐问题的 C 语言代码: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #include <unistd.h> #define N 5 // 哲学家的数 #define LEFT (i + N - 1) % N // 左侧哲学家的编号 #define RIGHT (i + 1) % N // 右侧哲学家的编号 int state[N]; // 哲学家的状态,0 表示思考,1 表示饥饿,2 表示进餐 sem_t mutex; // 互斥信号,保证每次只有一个哲学家拿起筷子 sem_t s[N]; // 每个哲学家对应的信号,表示他的左右两侧是否有可用的筷子 void test(int i) { if (state[i] == 1 && state[LEFT] != 2 && state[RIGHT] != 2) { state[i] = 2; // 进餐 printf("哲学家 %d 号拿起了筷子 %d 和 %d,开始进餐。\n", i, LEFT, i); sleep(2); // 模拟进餐时间 sem_post(&s[i]); // 放下左侧筷子 sem_post(&s[RIGHT]); // 放下右侧筷子 printf("哲学家 %d 号放下了筷子 %d 和 %d,开始思考。\n", i, LEFT, i); state[i] = 0; // 思考 } } void take_forks(int i) { sem_wait(&mutex); // 互斥 state[i] = 1; // 饥饿 printf("哲学家 %d 号正在等待筷子 %d 和 %d。\n", i, LEFT, i); test(i); sem_post(&mutex); sem_wait(&s[i]); // 左侧筷子 sleep(1); // 模拟拿起左侧筷子的时间 sem_wait(&s[RIGHT]); // 右侧筷子 sleep(1); // 模拟拿起右侧筷子的时间 } void put_forks(int i) { sem_wait(&mutex); // 互斥 state[i] = 0; // 思考 printf("哲学家 %d 号放下了筷子 %d 和 %d,开始思考。\n", i, LEFT, i); test(LEFT); // 左侧哲学家试图进餐 test(RIGHT); // 右侧哲学家试图进餐 sem_post(&mutex); } void *philosopher(void *arg) { int i = *(int *)arg; while (1) { sleep(1); // 模拟思考时间 take_forks(i); // 拿起筷子 sleep(1); // 模拟进餐时间 put_forks(i); // 放下筷子 } } int main() { pthread_t tid[N]; int i; sem_init(&mutex, 0, 1); for (i = 0; i < N; i++) { sem_init(&s[i], 0, 0); } for (i = 0; i < N; i++) { pthread_create(&tid[i], NULL, philosopher, (void *)&i); printf("哲学家 %d 号开始思考。\n", i); } for (i = 0; i < N; i++) { pthread_join(tid[i], NULL); } sem_destroy(&mutex); for (i = 0; i < N; i++) { sem_destroy(&s[i]); } return 0; } ``` 在这个代码中,每个哲学家都是一个线程,他们通过信号来协调各自的行为。当一个哲学家想要进餐时,他会首先试图拿起左右两侧的筷子,如果同时有其他哲学家在用,那么他就会等待。当他成功拿起筷子后,开始进餐,并在一定时间后放下筷子,继续思考。如果他放下筷子后发现左右两侧的哲学家也都饥饿了,那么他就会通知他们可以尝试拿起筷子进餐。 总之,这个代码中通过信号机制实现了哲学家进餐问题的同步和互斥,避免了和饿问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值