比如我们有一张桌子,上面坐着五位哲学家
现在他们每个人都有一双筷子,并且都拥有了自己的编号。
桌子上摆满了菜,哲学家们现在开始只做两件事情,吃饭,或者思考。
当他们吃饭的时候就停止思考 ,当他们思考的时候就停止吃饭。
我们假设他们都会用筷子,而当他们要吃饭的时候都必须拿两根筷子。
而且每个哲学家并不互相交流,此时就会出现一个很严重的问题。
如果这些哲学家在准备吃饭的时候,先拿起自己的筷子,再拿起自己左手边的筷子。当五名哲学家同时准备进餐的时候就会发现,自己的左手边都没有筷子可拿。此时就会产生死锁。
在这里,我们需要先了解死锁
死锁 :
死锁是指两个或两个以上的进程在执行过程中,由于资源竞争或彼此通信而造成的一种阻塞现象。若无外力作用,他们都将无法进行下去,此时称系统处于死锁状态或系统产生了死锁。
死锁产生的四个必要条件 :
1. 互斥
进程对所分配的资源进行排他性使用,即资源独占。如果有其他进程请求资源,那么其他进程只能等待,直到资源被释放。
2. 请求并保持
指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已经被占用。此时进程阻塞并对自己获得的其他资源不释放。
3. 不剥夺
进程获得的资源在未使用完前,不能被剥夺。只能通过进程自己释放。
4. 环路等待
发生死锁时,必须存在一个进程—资源的环形链。
例 :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <string.h>
#include <time.h>
int semid;
union semun{
int val;
};
void wait_for_1fork(int no) // 取出一根筷子
{
struct sembuf sbs[1] = {no, -1, 0};
semop(semid, sbs, 1);
}
void philosophere( int no )
{ // 哲学家开始进行思考/吃饭
srand(time(NULL));
while( 1 ){
sleep(rand()%3);
printf("%d think\n", no);
sleep(rand()%3);
printf("%d hungry\n",no);
wait_for_1fork(no);
sleep(rand()%2); // 间隔一段时间后拿起第二根筷子
wait_for_1fork((no+1)%5);
printf("%d eating\n",no);
put_for_2fork(no);
}
}
int main( void )
{
srand(time(NULL));
// 创建信号量
semid = semget(IPC_PRIVATE, 5, IPC_PRIVATE|0666);
if( semid == -1)
perror("semget"),exit(1);
union semun su;
su.val = 1;
int i;
for(i=0; i<5; i++)
semctl(semid, i ,SETVAL, su);
int no = 0;
for(i=1; i<5; i++){
// 我们使用不同的五个进程来模拟五位哲学家
pid_t pid = fork();
if( pid == 0){
no = i;
break;
}
}
philosophere(no);
}
可以看出,当哲学家们同时准备进行吃饭的时候,此时都在等待下左手边的筷子,而没有筷子可拿,便陷入了死锁状态。
为了解决这种情况。
我们可以先让哲学家 拿左手边的筷子,再拿自己的筷子,那