文章目錄
1.用信號量集解決哲學家就餐問題
- 信號量的個數不再是一個
如果5個哲學家同時處於飢餓的狀態,同時拿起左邊的叉子,想拿起右邊的叉子,但是拿不起來右邊的叉子,會導致死鎖的發生。
避免該死鎖問題:兩個叉子都滿足的情況下,哲學家才能拿起叉子進行用餐,要麼拿到2把叉子,要麼都不拿,這是原子操作
- eg:NetworkProgramming-master (1)\NetworkProgramming-master\P30sem03.c
//
// Created by wangji on 19-8-13.
//
// p30 system v信號量(二)
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <wait.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0);
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
int semid;
//睡眠的時間爲1-5s
#define DELAY (rand() % 5 + 1 )
//模擬死鎖
int wait_1fork(int no)
{
struct sembuf sb={no, -1 ,0};
int ret;
ret=semop(semid, &sb, 1);
if (ret == -1)
ERR_EXIT("semop");
return ret;
}
void get2fork(int pid)
{
unsigned short int left = pid;//左邊的刀叉編號=哲學家的id編號
unsigned short int right = (pid + 1) % 5;//右邊的刀叉編號=哲學家id編號+1,以此,得出來的經驗
struct sembuf sembuf[2] = {{left, -1, 0}, {right, -1, 0}};//刀叉的編號就是信號的序號
int ret = semop(semid, sembuf, 2);//對信號集中的2個信號量進行操作,要麼同時得到2個叉子,要麼都得不到,就處於等待狀態,等待別的哲學家歸還叉子
if (ret == -1)
{
ERR_EXIT("get2fork")
}
};
void put2fork(int pid)
{
unsigned short int left = pid;
unsigned short int right = (pid + 1) % 5;
struct sembuf sembuf[2] = {{left, 1, 0}, {right, 1, 0}};
int ret = semop(semid, sembuf, 2);
if (ret == -1)
{
ERR_EXIT("get2fork")
}
};
void philosopher(int no)
{
srand(getpid());//用了rand()隨機數,這裏給隨機數一個種子
while (1)
{
printf("%d is thinking\n", no);//表示哲學家思考
sleep(DELAY);//哲學家思考一段時間,哲學家餓了
printf("%d is hungry\n", no);
get2fork(no);//獲取2個叉子
printf("%d is eating\n", no);//吃飯
sleep(DELAY);//吃完飯了
put2fork(no);//釋放2個叉子
/*模擬死鎖
unsigned short int left = pid;
unsigned short int right = (pid + 1) % 5;
printf("%d is thinking\n", no);//表示哲學家思考
sleep(DELAY);//哲學家思考一段時間,哲學家餓了
printf("%d is hungry\n", no);
wait_1fork(left); //哲學家看到刀叉就拿起來
sleep(DELAY);//爲了更快的產生死鎖
wait_1fork(right); //哲學家看到刀叉就拿起來
printf("%d is eating\n", no);//吃飯
sleep(DELAY);//吃完飯了
put2fork(no);//釋放2個叉子
*/
}
}
int main(int argc, char** argv)
{
semid = semget(IPC_PRIVATE, 5, IPC_CREAT | IPC_EXCL | 0666);//創建的信號量集中有5個信號量,模擬5個叉子
if (semid == -1)
{
ERR_EXIT("semid");
}
union semun su;
su.val = 1;
for (int i = 0; i < 5; ++i)
{
semctl(semid, i, SETVAL, su);//初始化爲1表示都是可用的狀態
}
int no = 0;
pid_t pid;
for (int i = 1; i < 5; ++i)//創建4個子進程
{
pid = fork();
if (pid == -1)
ERR_EXIT("fork");
if (pid == 0)
{
no = i;
break;
}
}
philosopher(no);
return 0;
}
-
測試結果:
相鄰的2個哲學家不可能同時處於吃的狀態,也就是不可能出現死鎖的狀態
-
eg:模擬死鎖NetworkProgramming-master (1)\NetworkProgramming-master\P30sem03.c
//
// Created by wangji on 19-8-13.
//
// p30 system v信號量(二)
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <wait.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0);
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
int semid;
//睡眠的時間爲1-5s
#define DELAY (rand() % 5 + 1 )
//模擬死鎖
int wait_1fork(int no)
{
struct sembuf sb={no, -1 ,0};
int ret;
ret=semop(semid, &sb, 1);
if (ret == -1)
ERR_EXIT("semop");
return ret;
}
void get2fork(int pid)
{
unsigned short int left = pid;//左邊的刀叉編號=哲學家的id編號
unsigned short int right = (pid + 1) % 5;//右邊的刀叉編號=哲學家id編號+1,以此,得出來的經驗
struct sembuf sembuf[2] = {{left, -1, 0}, {right, -1, 0}};//刀叉的編號就是信號的序號
int ret = semop(semid, sembuf, 2);//對信號集中的2個信號量進行操作,要麼同時得到2個叉子,要麼都得不到,就處於等待狀態,等待別的哲學家歸還叉子
if (ret == -1)
{
ERR_EXIT("get2fork")
}
};
void put2fork(int pid)
{
unsigned short int left = pid;
unsigned short int right = (pid + 1) % 5;
struct sembuf sembuf[2] = {{left, 1, 0}, {right, 1, 0}};
int ret = semop(semid, sembuf, 2);
if (ret == -1)
{
ERR_EXIT("get2fork")
}
};
void philosopher(int no)
{
srand(getpid());//用了rand()隨機數,這裏給隨機數一個種子
while (1)
{
/*
printf("%d is thinking\n", no);//表示哲學家思考
sleep(DELAY);//哲學家思考一段時間,哲學家餓了
printf("%d is hungry\n", no);
get2fork(no);//獲取2個叉子
printf("%d is eating\n", no);//吃飯
sleep(DELAY);//吃完飯了
put2fork(no);//釋放2個叉子
*/
unsigned short int left = pid;
unsigned short int right = (pid + 1) % 5;
printf("%d is thinking\n", no);//表示哲學家思考
sleep(DELAY);//哲學家思考一段時間,哲學家餓了
printf("%d is hungry\n", no);
wait_1fork(left); //哲學家看到刀叉就拿起來
sleep(DELAY);//爲了更快的產生死鎖
wait_1fork(right); //哲學家看到刀叉就拿起來
printf("%d is eating\n", no);//吃飯
sleep(DELAY);//吃完飯了
put2fork(no);//釋放2個叉子
}
}
int main(int argc, char** argv)
{
semid = semget(IPC_PRIVATE, 5, IPC_CREAT | IPC_EXCL | 0666);//創建的信號量集中有5個信號量,模擬5個叉子
if (semid == -1)
{
ERR_EXIT("semid");
}
union semun su;
su.val = 1;
for (int i = 0; i < 5; ++i)
{
semctl(semid, i, SETVAL, su);//初始化爲1表示都是可用的狀態
}
int no = 0;
pid_t pid;
for (int i = 1; i < 5; ++i)//創建4個子進程
{
pid = fork();
if (pid == -1)
ERR_EXIT("fork");
if (pid == 0)
{
no = i;
break;
}
}
philosopher(no);
return 0;
}
- 測試結果:
5個哲學家都處於thinkng狀態,hungry狀態,5個哲學家同時都去拿起左叉子