文章目录
- 题目描述
- 代码实现
- 关于pipe函数
- 关于读写操作
- 关于读写端口
- 关于wait函数
- 功能:
- 注意:
- 关于fork函数
题目描述
编写一个程序,利用管道实现父子进程的通信,父进程向子进程发送信息,由子进程输出显示。
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //管道功能所在的头文件
#include <sys/types.h> //wait函数所在的头文件
#include <sys/wait.h> //wait函数所在的头文件#define MAXLINE 80int main()
{int n; //所发送消息的长度int fd[2]; //管道读写端口pid_t pid; //进程号char line[MAXLINE]; //消息缓冲区if(pipe(fd) < 0) //建立管道不成功{perror("pipe");exit(1); //有错误型的退出}if((pid = fork()) < 0) //建立子进程不成功{perror("fork:");exit(1);}else //成功建立子进程{ if(pid > 0) //父进程{close(fd[0]); //关闭读端write(fd[1],"I love CMY!\n", 12); //把"I love CMY!\n"长度为12的字符送到管道写端口fd[1]close(fd[1]); //关闭写端,老师是要求写完之后要关闭的,但是我试了试不写也没啥问题……wait(NULL); //父进程等待子进程结束}else //子进程{close(fd[1]); //关闭写端n = read(fd[0], line, MAXLINE); //从管道读端口fd[0]把长度为MAXLINE的字符送到line中write(STDOUT_FILENO, line, n); //将line中长度为n的字符写到标准输出设备(即屏幕上)close(fd[0]); //同上,关闭读端,老师是要求写完之后要关闭的,但是我试了试不写也没啥问题……} }return 0;
}
关于pipe函数
功能:创建一个普通管道
关于读写操作
也就是说读/写操作的流程是:
- 关闭读/写端
- 进行写/读操作
- 写/读完关闭写/读端
关于读写端口
为什么fd[0]是读,fd[1]是写,能不能颠倒过来?
一般来讲,我们常说:读写读写,不说写读写读,因为不顺口。所以0是读,1是写,你要是想颠倒也是可以的,只要你自己记得住就行。
关于wait函数
功能:
父进程一旦调用了wait就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
注意:
当父进程没有用wait()函数等待已终止的子进程时,子进程就会进入一种无父进程的状态,此时子进程就是僵尸进程。
如果先终止父进程,子进程依然会继续正常进行,只是它将由init进程(PID 1)继承,当子进程终止时,init进程捕获这个状态。
关于fork函数
其实本题就是管道和父子进程的相结合,重点是理解fork()
之后父子进程的并行执行
,以老师PPT中的例题为例:
子进程执行的是 val == 0 的内容,而父进程执行的是 val > 0 的内容,子进程创建的时候完全复制了父进程的资源,可以理解为自 val = fork() 之后,代码就被copy了一份一摸一样的,父进程执行被copy的,子进程执行copy的。而对于本题而言,从
if((pid = fork()) < 0) //建立子进程不成功
开始,子进程copy了后面的代码,而且继承了父进程之前的资源,如变量
等,然后在接下来的代码中根据pid的不同进入不同的代码段。
值得注意的是,本题代码中先处理的是父进程的写操作,再处理的是子进程的读操作,那如果反过来先写子进程的读操作,再写父进程的写操作,代码还可以正常运行吗?
经过测试,答案是可以,因为我们刚讲过他们俩是并行执行
嘛,但是根据先写进去再读出来比较符合人类的思维,所以我们本题就先写父进程的写操作,再处理子进程的读操作~
证据如下图: