1、实现两个进程之间互斥访问临界资源
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<linux/sem.h>
int mutexid;
int main()
{
int child, i, j;
struct sembuf p, v;
// 定义信号量,初值为1
mutexid = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
if (semctl(mutexid, 0, SETVAL, 1) == -1)
{
perror("semctl setval error");
}
// 定义p操作
p.sem_num = 0;
p.sem_op = -1;
p.sem_flg = SEM_UNDO;
// 定义v操作
v.sem_num = 0;
v.sem_op = 1;
v.sem_flg = SEM_UNDO;
child = fork();
while (1)
{
if (child == -1)
{
printf("error");
}
// 父进程
else if (child > 0)
{
i = 1;
while (i <= 3)
{
sleep(1);
semop(mutexid, &p, 1);
printf("print in\n");
sleep(1);
printf("print out\n");
semop(mutexid, &v, 1);
i++;
}
wait(NULL);
semctl(mutexid, IPC_RMID, 0);
exit(0);
}
// 子进程
else if (child == 0)
{
j = 1;
while (j <= 3)
{
sleep(1);
semop(mutexid, &p, 1);
printf("child in\n");
sleep(1);
printf("child out\n");
semop(mutexid, &v, 1);
j++;
}
}
}
return 0;
}
分析:
发现print in 和 print out之间和child in 、 child out之间都没有其他的输出,由此可见,两者进行之间不允许执行其他的操作。由于在输出print in 之前,进行了p操作,即申请资源,且存在一个信号量,所以其他进程只能等待,等print out之后进行v操作后可以执行其他进程。
2、不死锁的哲学家进餐问题
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<linux/sem.h>
int roomnum = 0;
int chopstick[5];
int P(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
// 进行p操作
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "P failed\n");
return 0;
}
return 1;
}
int V(int sem_id) // 释放资源
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
// 进行v操作
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "V failed\n");
return 0;
}
return 1;
}
int main()
{
roomnum = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
semctl(roomnum, 0, SETVAL, 4); // 至多只允许四个哲学家同时进餐
int i = 0;
int pid;
for (i = 0; i < 5; ++i)
{
chopstick[i] = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
semctl(chopstick[i], 0, SETVAL, 1);
}
for (i = 0; i < 5; ++i)
{
pid = fork();
if (pid == 0)
{
while (1)
{
// 哲学家在思考
printf("Philosopher %d is thinking,No disterb\n",i);
sleep(1);
// 哲学家饿了,准备开始吃饭
P(roomnum); //
printf("Philosopher %d is hungry,so he entered the room\n",i);
// 哲学家拿左筷子
P(chopstick[i]);
printf("Philosopher %d pick up left chopstick\n", i);
// 哲学家拿右筷子
P(chopstick[(i + 1) % 5]);
printf("Philosopher %d pick up right chopstick\n", i);
// 有两只筷子后,开始进餐
printf("Philosopher %d begins to eat!\n", i);
// 吃完饭了,释放右筷子
V(chopstick[(i + 1) % 5]);
printf("Philosopher %d pick down right chopstick\n", i);
// 吃完饭了,释放左筷子
V(chopstick[i]);
printf("Philosopher %d pick up left chopstick\n", i);
// 哲学家进餐结束
V(roomnum);
}
}
}
return 0;
}
分析:
哲学家进餐问题有三种解决方法:
方法一:最多只允许四位哲学家同时去拿做筷子,最终能保证至少有一位哲学家能进餐,并在用完后释放两只筷子供他人使用。
方法二:仅当哲学家的左右手都拿起时才允许进餐。换句话说,如果这个哲学家拿起左筷子没有右筷子能拿,拿就全部放下!
方法三:规定奇数号的哲学家先拿左筷子再拿右筷子,偶数好哲学家相反。
本题使用方法一解决,对四位哲学家初始4个信号量表示至多只允许四个哲学家同时进餐。创建五个子进程来表示五个哲学家的进餐情况,建立5个筷子的信号量,左右筷子同时存在即可进餐。
由于最多能有4个哲学家同时进餐,5个筷子。表示一定会有一个哲学家能有两只筷子,当该哲学家进餐完毕后,可以释放两只筷子给其他哲学家进餐使用,不会产生死锁。