编写c语言程序,模拟pv操作,实现题目:桌上有一只盘子,只可容纳n(0<n<5)个零食,每次只能放入或取出1个零食。爸爸向盘中放巧克力或者薯片或糖果;女儿1专等吃盘子中的糖果,女儿2专等吃盘子中的薯片,女儿3专等吃盘子中的巧克力。请用信号量和P、V操作来协调爸爸、女儿1、女儿2、女儿3之间的同步与互斥关系。
时间: 2024-03-09 21:51:03 浏览: 111
利用P、V操作实现进程同步与互斥
5星 · 资源好评率100%
下面是实现题目的C语言代码,使用了信号量和P、V操作来协调爸爸、女儿1、女儿2、女儿3之间的同步与互斥关系。
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define N 5 // 盘子中最多能装的零食数目
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
void P(int semid, int semnum) // P操作
{
struct sembuf sem;
sem.sem_num = semnum;
sem.sem_op = -1;
sem.sem_flg = SEM_UNDO;
if(semop(semid, &sem, 1) == -1)
{
perror("P operation error");
exit(1);
}
}
void V(int semid, int semnum) // V操作
{
struct sembuf sem;
sem.sem_num = semnum;
sem.sem_op = 1;
sem.sem_flg = SEM_UNDO;
if(semop(semid, &sem, 1) == -1)
{
perror("V operation error");
exit(1);
}
}
int main(int argc, char const *argv[])
{
int i, j, pid;
int semid, sem_key = 1234; // 信号量的键
int empty_sem, candy_sem, chip_sem, chocolate_sem; // 信号量的编号
union semun sem_union;
// 创建信号量集
if((semid = semget(sem_key, 4, IPC_CREAT | 0666)) == -1)
{
perror("Create semaphore error");
exit(1);
}
// 初始化信号量
sem_union.val = N;
if(semctl(semid, 0, SETVAL, sem_union) == -1) // 初始化empty_sem为N
{
perror("Set empty semaphore error");
exit(1);
}
sem_union.val = 0;
if(semctl(semid, 1, SETVAL, sem_union) == -1) // 初始化candy_sem为0
{
perror("Set candy semaphore error");
exit(1);
}
if(semctl(semid, 2, SETVAL, sem_union) == -1) // 初始化chip_sem为0
{
perror("Set chip semaphore error");
exit(1);
}
if(semctl(semid, 3, SETVAL, sem_union) == -1) // 初始化chocolate_sem为0
{
perror("Set chocolate semaphore error");
exit(1);
}
// 创建进程
for(i = 0; i < 4; i++)
{
pid = fork();
if(pid == -1)
{
perror("Create process error");
exit(1);
}
else if(pid == 0) // 子进程
{
switch(i)
{
case 0: // 爸爸放零食
for(j = 0; j < 20; j++)
{
P(semid, 0);
int rand_snack = rand() % 3; // 随机选择一种零食
switch(rand_snack)
{
case 0: // 放糖果
printf("爸爸放了一个糖果\n");
V(semid, 1);
break;
case 1: // 放薯片
printf("爸爸放了一个薯片\n");
V(semid, 2);
break;
case 2: // 放巧克力
printf("爸爸放了一个巧克力\n");
V(semid, 3);
break;
}
}
break;
case 1: // 女儿1吃糖果
for(j = 0; j < 10; j++)
{
P(semid, 1);
printf("女儿1吃了一个糖果\n");
V(semid, 0);
}
break;
case 2: // 女儿2吃薯片
for(j = 0; j < 10; j++)
{
P(semid, 2);
printf("女儿2吃了一个薯片\n");
V(semid, 0);
}
break;
case 3: // 女儿3吃巧克力
for(j = 0; j < 10; j++)
{
P(semid, 3);
printf("女儿3吃了一个巧克力\n");
V(semid, 0);
}
break;
}
exit(0);
}
}
// 等待子进程结束
for(i = 0; i < 4; i++)
{
wait(NULL);
}
// 删除信号量集
if(semctl(semid, 0, IPC_RMID, sem_union) == -1)
{
perror("Delete semaphore error");
exit(1);
}
return 0;
}
```
在上面的代码中,我们使用了一个长度为4的信号量集,其中:
- empty_sem表示盘子中可以放零食的数量,初始值为N;
- candy_sem表示盘子中糖果的数量,初始值为0;
- chip_sem表示盘子中薯片的数量,初始值为0;
- chocolate_sem表示盘子中巧克力的数量,初始值为0。
爸爸进程在放零食时,首先要获取empty_sem信号量,表示盘子中还有空位可以放零食;然后随机选择一种零食,放入盘子中,并将相应的零食信号量加1。
女儿进程在吃零食时,首先要获取相应的零食信号量,表示盘子中已经有相应的零食可以吃;然后吃掉一个零食,并将empty_sem信号量加1。
在代码运行时,我们可以发现爸爸进程和女儿进程的输出是交替出现的,这说明它们之间的同步关系得到了良好的协调。
阅读全文