常见的面试题:
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多进程编程——进程间通信相关推荐

  1. 2022-1-16 牛客C++项目 —— Linux多进程编程 —— waitpid函数

    复习用的问题 1.waitpid 函数介绍.从传入参数和返回值两个角度. 2.当传入的参数为什么的时候,这个函数的功能和 wait()函数的功能一致. /* #include <sys/type ...

  2. 仿牛客论坛项目(上)

    代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(下) 仿牛客论坛项目上 1. Spring 在测试类中使用Spring环境 @Primary的作用 @ ...

  3. 仿牛客论坛项目(下)

    代码仓库:https://gitee.com/qiuyusy/community 仿牛客论坛项目(上) 仿牛客论坛项目 15.kafka 1.阻塞队列 2.Kafka入门 简介 术语解释 下载 配置 ...

  4. 云服务器上部署仿牛客网项目

    云服务器上部署仿牛客网项目 安装JRE 安装Maven 安装MySQL 给mysql导入数据 安装Redis 安装kafka 安装ElasticSearch Wkhtmltopdf 安装tomcat ...

  5. Java面试题16 牛客 以下java程序代码,执行后的结果是()

    Java面试题16 牛客 以下java程序代码,执行后的结果是() 1 2 3 4 5 6 7 8 9 10 public class Test {     public static void ma ...

  6. 仿牛客社区项目笔记-帖子模块(核心)

    仿牛客社区项目笔记-帖子模块(核心) 1. 帖子模块 1.1 过滤敏感词 1.2 发布帖子 1.3 帖子详情 1.4 显示评论 1.5 添加评论 1.6 私信列表 1.7 发送私信 1. 帖子模块 分 ...

  7. 仿牛客社区项目(第一章)

    文章目录 第一章:初始 SpringBoot,开发社区首页 仿牛客社区项目开发首页功能 一. 实体引入 1. User类 2. DiscussPost 类 3. Page类 二. 配置文件 三. da ...

  8. 仿牛客论坛项目(3)

    仿牛客论坛项目 一.阻塞队列 1.1 测试 二.kafka入门 2.1 kafka下载 2.2 测试 三.Spring整合kafka 3.1 引入依赖 3.2 修改配置文件 3.3 测试 四.发布系统 ...

  9. 仿牛客论坛项目(5)

    仿牛客论坛项目 一.SpringSecurity入门案例 1.1 添加依赖 1.2 配置文件 1.3 工具类 CommunityUtil 1.4 配置类 SecurityConfig 1.5 实体类 ...

最新文章

  1. UVa 11624,两次BFS
  2. WINDOWS高级窗口的客户区域拖动技术及其应用
  3. Arrays.sort 不区分大小写 排序
  4. 学习AI可能不需要那么多数学知识:20小时进阶计划
  5. windows下的乱码问题
  6. py库: django (web框架)
  7. 现代交换技术学习笔记001
  8. 文件下载的java代码_文件下载java代码实现
  9. vue返回上一页面时回到原先滚动的位置
  10. java struts 读取文件_读取文件.txt并将其保存到c中的struct
  11. 遇到错误(firefox 打不开 重置winsock bug)
  12. 视频教程-webservice入门到精通(备java基础,xml,javaee框架)-Java
  13. Linux 串口驱动实例简单分析(x86 8250驱动(16550A),TIOCMGET, TIOCMSET, RTS)
  14. 科技文献检索与计算机应用试卷,科技文献检索试卷
  15. 美国大厂码农薪资曝光:年薪18万美元,够养家,不够买海景房
  16. webstorm 下载安装及破解
  17. 052试题 86 - crosscheck 命令及expried
  18. 如何通过纯javascript实现表单提交
  19. Regsvr32和Regasm注册DLL COM组件
  20. 读书笔记--推荐系统实践(4)

热门文章

  1. plex 乱码_如何优化电影和电视节目以流畅地播放Plex
  2. mysql期末考试试卷_MySQL数据库考试试题和答案
  3. MATLAB中语音加噪,语音信号加噪和降噪处理
  4. html5 驾考 答题样式,驾考科目四答题选择诀窍
  5. 单机十万并发HLS直播服务器的防盗链技术
  6. Zeppelin与Linkis、Scriptis的实践对比
  7. 一般人我不告诉他的15种App推广流氓手段(上)
  8. Kafka毒丸消息,危害,如何解决
  9. 用7行Python代码构建自己的有声读物
  10. python_安装模块后出错:无法启动程序丢失vcom140.dll