1. 程式人生 > >哲學家就餐問題——and型訊號量機制

哲學家就餐問題——and型訊號量機制

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>


#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/wait.h>


#ifdef_SEM_SEMUN_UNDEFINED
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
#endif


#defineERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
//相當於P操作
int wait_1chopstick(int no,int semid)
{
struct sembuf sb = {no,-1,0};
int ret;
ret = semop(semid,&sb,1);//semop()系統呼叫在semid標識的訊號量集中的訊號量上執行一個或多個up或down操作,可用於程序間的同步和互斥。
if(ret < 0) {
ERR_EXIT("semop");
}
return ret;
}
//相當於V操作
int free_1chopstick(int no,int semid)
{
struct sembuf sb = {no,1,0};
int ret;
ret = semop(semid,&sb,1);
if(ret < 0) {
ERR_EXIT("semop");
}
return ret;
}


#defineDELAY (rand() % 5 + 1)
//相當於P操作
void wait_for_2chopstick(int no,int semid)
{
//哲學家左邊的筷子號數
int left = no;
//右邊的筷子
int right = (no + 1) % 5;


//筷子值是兩個
//注意第一個引數是編號
struct sembuf buf[2] = {
{left,-1,0},   //左右兩隻筷子都能用時才進餐
{right,-1,0}
};
//訊號集中有5個訊號量,只是對其中的
//資源sembuf進行操作
semop(semid,buf,2);
}


//相當於V操作
void free_2chopstick(int no,int semid)
{
int left = no;
int right = (no + 1) % 5;
struct sembuf buf[2] = {
{left,1,0},
{right,1,0}
};
semop(semid,buf,2);
}




void philosophere(int no,int semid)
{
srand(getpid());
for(;;) {
       #if 1
//這裡採取的措施是當兩筷子都可用的時候
//哲學家才能吃飯,這樣不相鄰的哲學家就可
//吃上飯
printf("%d is thinking\n",no);
sleep(DELAY);
printf("%d is hungry\n",no);
wait_for_2chopstick(no,semid);//拿到筷子才能吃飯
printf("%d is eating\n",no);
sleep(DELAY);
free_2chopstick(no,semid);//釋放筷子
#else
//這段程式碼可能會造成死鎖
int left = no;
int right = (no + 1) % 5;
printf("%d is thinking\n",no);
sleep(DELAY);
printf("%d is hungry\n",no);
wait_1chopstick(left,semid);
sleep(DELAY);
wait_1chopstick(right,semid);
printf("%d is eating\n",no);
sleep(DELAY);
free_1chopstick(left,semid);
                free_1chopstick(right,semid);
#endif
}
}


int
main(int argc,char *argv[])
{
int semid;
//建立訊號量
semid = semget(IPC_PRIVATE,5,IPC_CREAT | 0666);
if(semid < 0) {
ERR_EXIT("semid");
}
union semun su;
su.val = 1;
int i;
for(i = 0;i < 5;++i) {
//注意第二個引數也是索引
semctl(semid,i,SETVAL,su);//semctl()系統呼叫在一個訊號量集或集合中的單個訊號量上執行各種控制操作
}
//建立4個子程序
int num = 0;
pid_t pid;
for(i = 1;i < 5;++i) {
pid = fork();
if(pid < 0) {
ERR_EXIT("fork");
}
if(0 == pid) {
num = i;
break;
}
}
//這裡就是哲學家要做的事情
philosophere(num,semid);//num 代表程序號
return 0;
}