首先这次测验采用的是封装的头文件:
在root角色中使用命令cd /usr/include touch ph_head.h vim ph_head.h
封装的头文件有:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdbool.h>
#include <dirent.h>
#include <time.h>
#include <math.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <linux/input.h>
#include <sys/mman.h>
【5-13-change】利用fork产生4个进程,模拟他们互斥写文件的过程:不是真写文件,是用输出语句输出“我要写文件”,“我正在写文件”,“我写完文件了”,输出体现出他们的互斥并发。两句“我正在写文件”不可能紧挨着输出。
代码:
#include<ph_head.h>
int file_ = 0;
char ch;
int main(int argc,char argv[])
{
pid_t pid;
pid_t pids[4];
int i = 0;
int j = 0;
int ph = 0;
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_flg = SEM_UNDO;
file_ = semget(IPC_PRIVATE,1,0666|IPC_CREAT);
semctl(file_,0,SETVAL,1);
for(i=0;i<=3;i++)
{
pid = fork();
if(pid==0)
{
while(1){
ph = rand()%4;
printf("ph program:进程%d 说---我要写文件\n",i+1);
sem_b.sem_op = -1;
semop(file_,&sem_b,1);//P-wait
printf("ph program:进程%d 说---我正在写文件\n",i+1);
sleep(3);
sem_b.sem_op = 1;
semop(file_,&sem_b,1);
printf("ph program:进程%d 说---我写完文件了\n",i+1);
}
}else{pids[i] = pid;}
}//for
do{
ch = getchar();
if(ch=='q')
for(i=0;i<=3;i++)
kill(pids[i],SIGTERM);
}while(ch!='q');}
运行截图1:
运行截图2:
总结分析:
- 因为fork产生四个进程,所以pid_t的数组中有4个元素;pid_t pids[4];
- 直接运用struct sembuf方法实现P、V操作;
- 定义整型变量file_,为设置为信号量,赋初值为1,表示可以写一个文件;
- 定义整型变量ph并运用rand()函数来随机生成值,达到四个进程公平竞争,因此在输出结果中发现顺序也不一样,因为rand()函数。
- 借用for循环中的变量i表明是哪个进程在写文件,同时显示的为进程1-4,而非0-3.
- 当输入’q’时表示运行完成。
【5-14】变化:信号量模拟实现进程并发,一个盘子只能放1个水果,母亲放苹果,父亲放桔子,儿子吃苹果,女儿吃桔子,利用printf输出字符串模拟母亲和孩子的动作,如输出“放苹果”,“吃桔子”等。孩子吃水果速度用sleep随机时间控制,要求输出应能体现正确同步逻辑顺序。
代码:
#include<ph_head.h>
int e_ph;//empty of plate
int f_ph;//fruit
int apple_ph;
int orange_ph;
int waitsem(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id,&sem_b,1)==-1)
{
fprintf(stderr,"ph program:P failed \n");
return 0;}
return 1;
}
int signalsem(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id,&sem_b,1)==-1)
{
fprintf(stderr,"V failed \n");
return 0;}
return 1;
}
int main(int argc,char argv[])
{
pid_t pid;
pid_t pids[4];
int i = 0;
char ch;
e_ph = semget(IPC_PRIVATE,1,0666|IPC_CREAT);
f_ph = semget(IPC_PRIVATE,1,0666|IPC_CREAT);
apple_ph = semget(IPC_PRIVATE,1,0666|IPC_CREAT);
orange_ph = semget(IPC_PRIVATE,1,0666|IPC_CREAT);
semctl(e_ph,0,SETVAL,1);//大于0表示盘子可以放,1为盘子可放数量
semctl(f_ph,0,SETVAL,0);//f为是否有水果,0为没有
semctl(apple_ph,0,SETVAL,0);//apple为是否有苹果,0为没有
semctl(orange_ph,0,SETVAL,0);//orange为是否有桔子,0为没有
for(i=0;i<=3;i++)
{
pid = fork();
if(pid>0) pids[i] = pid;
if(pid==0&&i==0)//father
while(1)
{
waitsem(e_ph);
sleep(5);
signalsem(f_ph);
signalsem(orange_ph);
printf("ph program:父亲已经放好桔子\n");}
if(pid==0&&i==1)//mother
while(1)
{
waitsem(e_ph);
sleep(5);
signalsem(f_ph);
signalsem(apple_ph);
printf("ph program:母亲已经放好苹果\n");}
if(pid==0&&i==2)//daughter
while(1)
{
printf("ph program:女儿想吃桔子\n");
waitsem(f_ph);
waitsem(orange_ph);
printf("ph program:女儿正在吃桔子\n");
sleep(rand()%6);
signalsem(orange_ph);
signalsem(e_ph);
printf("ph program:女儿吃完了桔子\n");
}
if(pid==0&&i==3)
while(1)
{
printf("ph program:儿子想吃苹果\n");
waitsem(f_ph);
waitsem(apple_ph);
printf("ph program:儿子正在吃苹果\n");
sleep(rand()%6);
signalsem(apple_ph);
signalsem(e_ph);
printf("ph program:儿子吃完了苹果\n");
}
}//for
do{
ch = getchar();
if(ch=='q')
for(i=0;i<=3;i++)
kill(pids[i],SIGTERM);
}while(ch!='q');
}//main
运行截图1:
运行截图2:
分析总结:
- 因为fork产生四个进程,所以pid_t的数组中有4个元素;pid_t pids[4];
- 将struct sembuf方法封装在waitsem和signalsem,通过调用waitsem和signalsem实现P、V操作
3.定义整型变量e_ph,f_ph,apple_ph和orange_ph,为设置为信号量:
e_ph表示大于0表示盘子可以放,1为盘子可放数量,赋初值为1;
f_ph表示是否有水果,0为没有,赋初值为0;
apple_ph表示是否有苹果,0为没有,赋初值为0;
orange_ph表示是否有桔子,0为没有,赋初值为0;
4.运用rand()函数来随机生成值,实现孩子吃水果速度用sleep随机时间控制,这因此也是输出结果中唯一的不同(时间不同),因为rand()函数。
5.运用for循环顺序的进行四个行为的进行。
对此我也尝试了使用rand()函数达到随机的效果,但是发现有个问题,就是信号量可以限制住苹果和桔子是否放和单一水果的效果,但是对于儿子和女儿来说,他们可以多次表示想吃苹果/桔子,有时候会连着输出两句“儿子想吃苹果”或者“女儿想吃桔子”,因此rand()不好用。
6.当输入’q’时表示运行完成。