2022-1-16牛客C++项目——Linux多进程编程——进程间通信
常见的面试题:
1、你知道进程间通信的方式有哪几种吗?
2、这个通信方式具体的实现原理是什么?怎么实现的?
复习时候需要使用的问题:
1、进程间的通信是什么?进程间为什么需要通信?
2、进程间通信的目的是什么?(有四个理由)
一、进程间为什么需要通信?
进程是一个独立的分配资源的单位,这意味着,进程与进程之间是无法访问对方的资源的。但是进程之间的协作需要知道其他进程之间的状态信息,这需要通过通信来交换数据。(共享一个数据块里头的信息)
二、进程间通信的目的是什么?
1、数据传输
2、事件通知(比如一个进程终止的时候需要发送消息给父进程)
3、资源共享(进程之间共享同一块数据资源,需要内核提供互斥和同步的机制)
4、进程控制(有些进程需要完全控制另外一个进程的运行,比如 用 gcc 来 debug。此时这个进程需要知道另外一个进程的运行状态,异常和终端的情况)
三、进程之间的通信方式有哪些?
匿名管道的使用例子:
四、管道的特点
管道其实是在内核区域中能够存储数据的一块缓冲区。
管道的文件特质体现在哪里?
管道两端是文件操作符:输入和输出的文件操作符。
匿名管道多用于两个有关系的进程之间的通信,如父子进程。
有名管道多用于没有关系的进程之间的通信。
如何理解字节流:
流里面的数据是没有格式的,也没有所谓开头和结尾的分隔符,读取的时候可以按照基本的数据类型的格式读取。也可以按照任意的大小读取。
五、为什么匿名管道可以用于有关系的进程之间的通信?
父进程在 fork 子进程的时候会拷贝一份文件描述符,因此父子进程的文件描述符指向同样的文件。而匿名管道就是通过文件描述符来读取和写入数据的。拥有同样的文件描述符说明可以对同一个匿名管道进行操作。
六、管道的数据结构
管道的数据结构是一个环形的队列,是半双工的。
/*
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建一个匿名管道,用于进程间的通信
参数:传出参数。(那不得malloc)pipefd[0] 读端的文件描述符pipefd[1] 写端的文件描述符
返回值:
-成功:0
-失败:-1,并且设置 perror
注意:匿名管道只能用于具有关系的进程间的通信,比如说(父子进程,兄弟进程,孙子进程)*/
//子进程发送数据给父进程,父进程读取到数据之后读出
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
int main(void){//管道创建,需要在 fork 之前还是在 fork 之后?//需要在 fork 之前创建,感觉在 fork 之后创建会导致创建了两个管道int pipefd[2];int ret = pipe(pipefd);if(ret == -1){perror("pipe");exit(0);}pid_t pid = fork();if(pid > 0){char buf[1024] = {0};int len = read(pipefd[0],buf,sizeof(buf));printf("parent recv : %s ,pid : %d.\n",buf,getpid());}else if(pid == 0){char *str = "hello, i am child.";int len = write(pipefd[1],str,strlen(str));
//sizeof运算符计算出来的是字节,计算最后的'\0'
//strlen 函数计算出来的是字符串的长度,不包括最后面的'\0'}
}
管道默认是阻塞的,如果管道中没有数据,则 read 阻塞,如果管道已经写满了数据,则 write 阻塞。
/*
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建一个匿名管道,用于进程间的通信
参数:传出参数。(那不得malloc,不用)pipefd[0] 读端的文件描述符pipefd[1] 写端的文件描述符
返回值:
-成功:0
-失败:-1,并且设置 perror
注意:匿名管道只能用于具有关系的进程间的通信,比如说(父子进程,兄弟进程,孙子进程)*/
//子进程发送数据给父进程,父进程读取到数据之后读出
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
int main(void){//管道创建,需要在 fork 之前还是在 fork 之后?//需要在 fork 之前创建,感觉在 fork 之后创建会导致创建了两个管道int pipefd[2];int ret = pipe(pipefd);if(ret == -1){perror("pipe");exit(0);}pid_t pid = fork();if(pid > 0){char buf[1024] = {0};int len = read(pipefd[0],buf,sizeof(buf));printf("parent recv : %s ,pid : %d.\n",buf,getpid());}else if(pid == 0){sleep(10);//通过延后写入数据来达到管道阻塞的效果//延后写入数据会造成父进程在读数据的时候无数据可以读,父进程阻塞,终端显示程序输出滞后char *str = "hello, i am child.";int len = write(pipefd[1],str,strlen(str));
//sizeof运算符计算出来的是字节,计算最后的'\0'
//strlen 函数计算出来的是字符串的长度,不包括最后面的'\0'}
}
观察运行效果的时候,肉眼可见的阻塞了好久。
子进程持续向父进程发送数据,
父子程序同时写入和读出数据,会导致读到自己写入的数据。
/*
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建一个匿名管道,用于进程间的通信
参数:传出参数。(那不得malloc)pipefd[0] 读端的文件描述符pipefd[1] 写端的文件描述符
返回值:
-成功:0
-失败:-1,并且设置 perror
注意:匿名管道只能用于具有关系的进程间的通信,比如说(父子进程,兄弟进程,孙子进程)*/
//子进程发送数据给父进程,父进程读取到数据之后读出
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
int main(void){//管道创建,需要在 fork 之前还是在 fork 之后?//需要在 fork 之前创建,感觉在 fork 之后创建会导致创建了两个管道int pipefd[2];int ret = pipe(pipefd);if(ret == -1){perror("pipe");exit(0);}pid_t pid = fork();if(pid > 0){printf("i am parent process, pid : %d .\n",getpid());while (1){char buf[1024] = {0};int len = read(pipefd[0],buf,sizeof(buf));printf("parent recv : %s ,pid : %d.\n",buf,getpid());}}else if(pid == 0){printf("i am child process, pid : %d .\n",getpid());// sleep(10);//通过延后写入数据来达到管道阻塞的效果while (1){char *str = "hello, i am child.";int len = write(pipefd[1],str,strlen(str));sleep(1);}//sizeof运算符计算出来的是字节,计算最后的'\0'
//strlen 函数计算出来的是字符串的长度,不包括最后面的'\0'}
}
父子进程能够通过管道向对方发送数据。
但是不可以同时先读,同时先读管道里面没有数据会造成阻塞。
如果同时先写会怎么样?
同时先写的运行结果,会得到自己写入的数据。
在写入数据之后都使用 sleep(1)来达到进程切换的目的,保证自己能够读到对方写入的数据。
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
int main(void){//管道创建,需要在 fork 之前还是在 fork 之后?//需要在 fork 之前创建,感觉在 fork 之后创建会导致创建了两个管道int pipefd[2];int ret = pipe(pipefd);if(ret == -1){perror("pipe");exit(0);}pid_t pid = fork();if(pid > 0){printf("i am parent process, pid : %d .\n",getpid());while (1){char buf[1024] = {0};int len1 = read(pipefd[0],buf,sizeof(buf));printf("parent recv : %s ,pid : %d.\n",buf,getpid());char *str = "hello, i am parent.";int len2= write(pipefd[1],str,strlen(str));sleep(1);}}else if(pid == 0){printf("i am child process, pid : %d .\n",getpid());// sleep(10);//通过延后写入数据来达到管道阻塞的效果while (1){char *str = "hello, i am child.";int len1 = write(pipefd[1],str,strlen(str));sleep(1);char buf[1024] = {0};int len2 = read(pipefd[0],buf,sizeof(buf));printf("child recv : %s ,pid : %d.\n",buf,getpid());}
//sizeof运算符计算出来的是字节,计算最后的'\0'
//strlen 函数计算出来的是字符串的长度,不包括最后面的'\0'}
}
查看管道的大小
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
int main(void){int pipefd[2];int ret = pipe(pipefd);if(ret == -1){perror("pipe");exit(0);}//fpathconf()获取文件相关的配置信息long size = fpathconf(pipefd[0],_PC_PIPE_BUF);printf("pipe size : %ld \n",size);}
使用 ulimits -a命令来查看
两者的结果是一致的。
三、匿名管道通信案例
如果子进程和父进程同时写,或者是写完之后读取的速度太块,会读到自己写的内容,这个是为什么?
正常的数据流向:
读到自己的内容的数据的流向:
个人觉得应该采用两个管道。。。。。
一般采用匿名管道都是一个进程读取一个进程写,如果两个进程都读都写会混乱。
上面的第一个示例程序当中会让进程休眠,交出 CPU时间片,所以不会出现这样的幺蛾子。
可以通过关闭文件操作符来关闭进程对管道读端和写端的控制。
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
int main(void){int pipefd[2];int ret = pipe(pipefd);if(ret == -1){perror("pipe");exit(0);}pid_t pid = fork();if(pid > 0){printf("i am parent process, pid : %d .\n",getpid());//父进程如果不写数据可以将写端关闭了close(pipefd[1]);while (1){char buf[1024] = {0};int len1 = read(pipefd[0],buf,sizeof(buf));printf("parent recv : %s ,pid : %d.\n",buf,getpid());}}else if(pid == 0){printf("i am child process, pid : %d .\n",getpid());//子进程如果不读数据可以将读端关闭了close(pipefd[0]);while (1){char *str = "hello, i am child.";int len1 = write(pipefd[1],str,strlen(str));} }
}
四、使用管道进行通信的案例
/*
实现 ps aux | grep XXX 父子进程间的通信
子进程 : ps aux,子进程结束后, 将数据发送给父进程
父进程:获取到数据,过滤pipe()
execlp()
子进程将指向终端的标准输出重定向到管道的写端
*/
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<string.h>
int main(void){//创建管道int pipefd[2];int ret = pipe(pipefd);if(ret == -1){perror("pipe");exit(0);}// return 0;//创建子进程pid_t pid = fork();if(pid > 0){//父进程//关闭写段close(pipefd[1]);//从管道中读取,但是这种写法只能读取一次char buf[1024];// int len = read(pipefd[0],buf,sizeof(buf)-1);// printf("%s",buf);//循环读取int len = -1;while ((len = read(pipefd[0],buf,sizeof(buf)-1)) > 0){printf("%s",buf);}//}else if(pid == 0){//子进程//关闭读端close(pipefd[0]);//文件描述符的重定向 STDOUT_FILENO->fd[1]//否则会在当前的终端中输出dup2(pipefd[1],STDOUT_FILENO);//执行 ps auxexeclp("ps","ps","aux",NULL);perror("execlp");exit(0);}else{perror("fork");exit(0);}return 0;}
输出的内容有限,因为管道的缓冲区的大小有限,写满了之后就无法继续写入。
2022-1-16牛客C++项目——Linux多进程编程——进程间通信相关推荐
- 2022-1-16 牛客C++项目 —— Linux多进程编程 —— waitpid函数
复习用的问题 1.waitpid 函数介绍.从传入参数和返回值两个角度. 2.当传入的参数为什么的时候,这个函数的功能和 wait()函数的功能一致. /* #include <sys/type ...
- 仿牛客论坛项目(上)
代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(下) 仿牛客论坛项目上 1. Spring 在测试类中使用Spring环境 @Primary的作用 @ ...
- 仿牛客论坛项目(下)
代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(上) 仿牛客论坛项目 15.kafka 1.阻塞队列 2.Kafka入门 简介 术语解释 下载 配置 ...
- 云服务器上部署仿牛客网项目
云服务器上部署仿牛客网项目 安装JRE 安装Maven 安装MySQL 给mysql导入数据 安装Redis 安装kafka 安装ElasticSearch Wkhtmltopdf 安装tomcat ...
- Java面试题16 牛客 以下java程序代码,执行后的结果是()
Java面试题16 牛客 以下java程序代码,执行后的结果是() 1 2 3 4 5 6 7 8 9 10 public class Test { public static void ma ...
- 仿牛客社区项目笔记-帖子模块(核心)
仿牛客社区项目笔记-帖子模块(核心) 1. 帖子模块 1.1 过滤敏感词 1.2 发布帖子 1.3 帖子详情 1.4 显示评论 1.5 添加评论 1.6 私信列表 1.7 发送私信 1. 帖子模块 分 ...
- 仿牛客社区项目(第一章)
文章目录 第一章:初始 SpringBoot,开发社区首页 仿牛客社区项目开发首页功能 一. 实体引入 1. User类 2. DiscussPost 类 3. Page类 二. 配置文件 三. da ...
- 仿牛客论坛项目(3)
仿牛客论坛项目 一.阻塞队列 1.1 测试 二.kafka入门 2.1 kafka下载 2.2 测试 三.Spring整合kafka 3.1 引入依赖 3.2 修改配置文件 3.3 测试 四.发布系统 ...
- 仿牛客论坛项目(5)
仿牛客论坛项目 一.SpringSecurity入门案例 1.1 添加依赖 1.2 配置文件 1.3 工具类 CommunityUtil 1.4 配置类 SecurityConfig 1.5 实体类 ...
最新文章
- UVa 11624,两次BFS
- WINDOWS高级窗口的客户区域拖动技术及其应用
- Arrays.sort 不区分大小写 排序
- 学习AI可能不需要那么多数学知识:20小时进阶计划
- windows下的乱码问题
- py库: django (web框架)
- 现代交换技术学习笔记001
- 文件下载的java代码_文件下载java代码实现
- vue返回上一页面时回到原先滚动的位置
- java struts 读取文件_读取文件.txt并将其保存到c中的struct
- 遇到错误(firefox 打不开 重置winsock bug)
- 视频教程-webservice入门到精通(备java基础,xml,javaee框架)-Java
- Linux 串口驱动实例简单分析(x86 8250驱动(16550A),TIOCMGET, TIOCMSET, RTS)
- 科技文献检索与计算机应用试卷,科技文献检索试卷
- 美国大厂码农薪资曝光:年薪18万美元,够养家,不够买海景房
- webstorm 下载安装及破解
- 052试题 86 - crosscheck 命令及expried
- 如何通过纯javascript实现表单提交
- Regsvr32和Regasm注册DLL COM组件
- 读书笔记--推荐系统实践(4)
热门文章
- plex 乱码_如何优化电影和电视节目以流畅地播放Plex
- mysql期末考试试卷_MySQL数据库考试试题和答案
- MATLAB中语音加噪,语音信号加噪和降噪处理
- html5 驾考 答题样式,驾考科目四答题选择诀窍
- 单机十万并发HLS直播服务器的防盗链技术
- Zeppelin与Linkis、Scriptis的实践对比
- 一般人我不告诉他的15种App推广流氓手段(上)
- Kafka毒丸消息,危害,如何解决
- 用7行Python代码构建自己的有声读物
- python_安装模块后出错:无法启动程序丢失vcom140.dll