二、实验要求及完成情况
实验要求 :
实验 11c -3 pv 操作-同步
- 写进程向缓冲区写入内容,读进程读出。
- 用pv操作实现读写进程间的同步。
完成情况 :
本实验通过用父子进程来模拟读者和写者,并完成他们之间通信的同步操作。具体来讲,首先将读者和写者之间的”桥梁”—临界区用文件来代替,子进程作为写者向文件中写数据,父进程作为读者向文件中读数据,读完数据并清空数据(相当于模拟了取走数据)。
三、设计与实现
同步的示意图 :
定义两个变量 emptyid 和 fullid ,作为同步信号量。在上面的图中表示 s1 和 s2 。
在读者中 :
在写者中:
思路 : 用fork() 创建子进程,子进程写数据,父进程读数据,临界区是文件。
流程图
四、运行结果及分析
运行结果
五、源码
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/sem.h>
#include<sys/shm.h>
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
};
int emptyid;
int fullid; //同步信号量
int main(int argc , char *argv[])
{
int chld;
struct sembuf P,V;
union semun arg;
char tmp[128] ;
int shmid;
char buffer[256];
//申请只有一个信号量的信号量集
FILE *fd1 ,*fd2 ;
emptyid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
fullid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
//分别对每个信号量赋初值
arg.val=1;
if(semctl(emptyid,0,SETVAL,arg)==-1)
perror("semctl setval error");
arg.val=0;
if(semctl(fullid,0,SETVAL,arg)==-1)
perror("semctl setval error");
//定义PV操作
P.sem_num=0;
P.sem_op=-1;
P.sem_flg=SEM_UNDO;
V.sem_num=0;
V.sem_op=1;
V.sem_flg=SEM_UNDO;
while((chld=fork())==-1);
if(chld>0)
{// 父进程
while(1)
{
semop(fullid,&P,1);
fd2 = fopen(argv[1],"r") ;
fscanf(fd2,"%s",tmp) ;
printf("父进程 reading-----\n") ;
printf("ytu.txt 's content is : %s \n",tmp) ;
// 父进程读完数据要清空
fclose(fd2) ;
fd2 = fopen(argv[1],"w") ;
fclose(fd2) ;
semop(emptyid,&V,1); // 告诉子进程可以写了
if(strncmp(tmp,"end",3)==0)
break;
}
wait(0);
printf("Parent exit!\n");
exit(0);
}
else
{ // 子进程完成写
while(1)
{
//fd1 = fopen(argv[1] ,"w") ; // 只写
semop(emptyid,&P,1);
fd1 = fopen(argv[1],"a") ;
// 只写追加 ,保证是父进程先将文件里的数据读出并清空,
// 而不是子进程覆盖的数据
puts("Enter your text:");
printf("子进程 writing ---\n") ;
scanf("%s",buffer);
fprintf(fd1,"%s",buffer);// 写入到文件中
// printf("write : %s \n" ,buffer) ;
fclose(fd1) ;
semop(fullid,&V,1);
if(strncmp(buffer,"end",3)==0)
{
sleep(1);
break;
}
}
printf("Child exit!\n");
exit(0);
}
return 0 ;
}