lab10 进程通信–管道
一.使用pipe创建管道,实现父子进程间的通信
1.代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int main(void){
int data_processed;
int file_pipes[2];
const char some_data[]="Hello world!";
char buffer[BUFSIZ+1];
pid_t fork_result;
memset(buffer,'\0',sizeof(buffer));
if(pipe(file_pipes)==0){
fork_result=fork();
if(fork_result==-1){
fprintf(stderr,"fork failure");
exit(EXIT_FAILURE);
}
if(fork_result==0){
data_processed=read(file_pipes[0],buffer,BUFSIZ);
printf("Read %d bytes: %s\n",data_processed,buffer);
exit(EXIT_SUCCESS);
}
else{
data_processed=write(file_pipes[1],buffer,strlen(some_data));
printf("write %d bytes\n",data_processed);
}
}
exit(EXIT_SUCCESS);
}
代码释义:使用pipe创建管道,在父子进程间通信
1.pipe()创建管道,fork()创建进程
2.fork()成功,父进程通过write()数据写到管道中
3.子进程用read()从管道中读出数据
运行如图:
二.用sort命令打开管道,然后对一个字符数组排序
1.代码:
#include<stdio.h>
#include<stdlib.h>
#define MAXSTRS 5
int main(){
int cntr;
FILE *pipe_fp; //**
char *strings[MAXSTRS]={"echo","bravo","alpha","charlie","delta"};
if((pipe_fp=popen("sort","w"))==NULL){
perror("popen");
exit(1);
}
for(cntr=0;cntr<MAXSTRS;cntr++){
fputs(strings[cntr],pipe_fp); //
fputc('\n',pipe_fp);
}
pclose(pipe_fp);
return 0;
}
代码释义:用sort命令打开一个管道,然后对字符数组排序
1.popen创建管道,并启动“sort"进程
2.如果管道创建成功,将无序数据写到管道中,sort()将无序数据排序
运行如图:
三.两个子进程通过管道传输数据
1.代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(){
pid_t pid1,pid2;
char *argv1[]={"pstree","-a",0};
char *argv2[]={"grep","login",0};
int fd[2];
if(pipe(fd)<0)
printf("create pipe error");
if((pid1=fork())==0){ //管道上游进程
close(fd[0]); //关闭管道读取端口
close(1); //关闭最初的标准输入
dup(fd[1]); //管道的写入端改为文件描述符1
close(fd[1]); //关闭打开文件描述符的一个副本
if(execvp("pstree",argv1)==-1) //启动运行程序
printf("come on");
}
if((pid2=fork())==0){ //管道下游进程
close(fd[1]); //关闭管道写入端口
close(0); //关闭最初的标准输入
dup(fd[0]); //管道的读取端改为文件描述符的一个副本
close(fd[0]); //关闭打开文件描述符的一个副本
execvp("grep",argv2); //启动运行程序
}
else{
close(fd[0]);
close(fd[1]);
wait(NULL);
wait(NULL);
}
return 0;
}
代码释义:该例程含有一个父进程和两个子进程,通过管道实现shell命令"pstree|grep login"
实现过程:
1.pipe()创建管道,fork()创建两个子进程,分别居于管道上下游
2.上游进程使用close(pipefd[0])关闭管道读取端,close(1)关闭最初的标准输出,
使用dupipe(pipefd[0])将管道的写入端改为文件描述符1,
使用close(pipefd[1])关闭文件描述符的一个副本,调用execvp启动运行程序
3.下游进程使用close(pipefd[1])关闭管道写入端,使用close(0)关闭最初的标准输入,
使用dup(pipefd[0])将管道的读取端改为文件描述符0,
使用close(pipefd[0])关闭文件描述符的一个副本,调用execvp()启动运行程序
运行如图:
四.多进程的管道通信
1.代码:
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
int pid1,pid2;
int main(void){
int fd[2];
int i;
char outpipe[200],inpipe[200];
pipe(fd); //创建一个管道
while((pid1=fork())==-1);
if(pid1==0){
lockf(fd[1],1,0);
for(i=0;i<3;i++){ //把输出串放入数组outpipe中
sprintf(outpipe,"child 1 %d %d is sending message\n",i,getpid());
write(fd[1],outpipe,50); //向管道写入长为50的串
sleep(1); //自我阻塞1秒
}
lockf(fd[1],0,0);
exit(0);
}
else{
while((pid2=fork())==-1);
if(pid2==0){
lockf(fd[1],1,0); //互斥
for(i=0;i<3;i++){
sprintf(outpipe,"child 2 %d %d is sending message\n",i,getpid());
write(fd[1],outpipe,50);
sleep(1);
}
lockf(fd[1],0,0);
exit(0);
}
else{
wait(0);
wait(0); //同步
printf("father %d\n",getpid());
for(i=0;i<6;i++){
read(fd[0],inpipe,50); //从管道中读取长为50的串
printf("%s\n",inpipe);
}
}
}
}
代码释义:多进程的管道通信
1.用pipe创建管道,子进程P1,P2分别向管道多次发送数据:
child 1 is sending message!
child 2 is sending message!
2.父进程从管道中读取子进程信息并显示
运行如图:
五.编写程序
1.程序要求:(跟着例四代码写就好了)
1.假设系统有三个并发程序:read,move,print,两个共享缓冲区b1,b2;
2. read:从输入设备记录一个记录,并存入缓冲区b1
move:从b1中取出一个记录,加工后放入缓冲区b2
print:取出b2中的一个记录,并打印
3.b1,b2每次只能放一个记录
4.要求三个进程协调,使得打印出来的数据与输入的数据次序,个数完全一致。
2.流程图:
3.代码:
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
int pid1,pid2;
int i;
char ch;
void scanfALine(char result[]){ //以一行为输入结果,scanf()以空格或者换行符进行输入结果
while(1){
scanf("%c",&ch);
if(ch=='\n')
break;
result[i++]=ch;
}
result[i]='\0';
}
int main(void){
int fd0[2],fd1[2]; //管道
char readpipe[200],movepipe[200];
pipe(fd0);
pipe(fd1);
if(pid1=fork()==0){
if(pid2=fork()==0){ //孙子进程: 向fd0管道写入
printf("Read:Please enter:");
scanfALine(readpipe);
write(fd0[1],readpipe,50);
exit(0);
}
else{ //儿子进程: 从fd0管道读出;修改;向fd1管道写入
wait(0);
read(fd0[0],movepipe,50); //从fd0管道中读出
printf("Move: %s\n",movepipe);
printf("Move:Please modify it:"); // 新写字符串直接覆盖之前的movepipe中的字符串
scanfALine(movepipe);
write(fd1[1],movepipe,50);
exit(0);
}
}
else{ //父亲进程: 从fd1管道读出
wait(0);
wait(0);
read(fd1[0],movepipe,50);
printf("Print: %s\n",movepipe);
exit(0);
}
}
//1.lockf()?
//2.两个管两个向 还是一个管道三个向 ?
//3.为啥写入含空格的字符串出错?
//4.为什么会覆盖掉之前的字符串?
//5.为什么修改后写不进去?
//任务:
//1.完成写入,移动,打印的管道架构
//2.用户自己写入
//3.用户修改
运行如图: