当前位置: 首页> 教育> 幼教 > Linux 进程通信

Linux 进程通信

时间:2025/7/27 23:44:50来源:https://blog.csdn.net/qincjun/article/details/139722244 浏览次数:0次

1.什么是进程通信?

答:两个或多个进程实现数据层面的交互;但是因为进程的独立性,导致进程通信的成本较高;

2.为什么要通信?

答:多进程之间由协同的需求,所以通信;以下是通信要实现的目的:

2.1.基本数据:

2.2.发送命令:一个进程控制另一个进程

2.3.多进程之间实现协同

2.4.通知

2.6.通信是有成本的:因为是要打破进程的独立性

3.怎么通信?

3.1进程间通信的本质:必须让不同的进程看到同一份“资源”

3.2“资源”——特定形式的内存空间;

3.3这个资源谁提供?答:一般是操作系统提供;

3.4为什么不是我们两个进程中的一个提供呢?答:进程具有独立性;假设是由一个进程提供,这个资源应该属于谁?他不是共享资源,还是进程独有,因为破环了进程的独立性;OS是第三方空间,谁用谁申请

3.5进程访问这个空间,进行通信,本质就是访问操作系统;进程代表的就是用户;“资源”从创建、使用、释放——必须调用系统接口;

3.6操作系统提供资源,保障了进程通信,而且底层设计、接口设计、都要由操作系统独立设计;一般操作系统,会有一个独立的通信模块——隶属于文件系统——IPC通信模块(进程间通信的意思)

3.7进程间通信是由标准的;两套标准——system V  和 posix

3.8基于文件级别的通信方式——管道(此时的文件,只是代称,我可以往内存中写啊)

思想是正确的,但是效率并不高;管道是Linux(unix)最古老的进程通信方式;

3.9管道原理(自我理解):基础IO部分,缓冲区里的数据要写入磁盘文件,现在不写入磁盘,而是直接与子进程交互,把数据给子进程;并且通过引用计数原理(智能指针)控制着文件的打开和关闭,进行读写;(只能单向通信所以命名为管道)

3.10强烈建议如果单向通信,一定要关闭不必要的文件描述符,防止写错;

3.11 如果我要进行双向通信呢——答:建两个管道;

3.12 以上讲的是父子进程,如果没有任何关系,可以用以上讲的原理进行通信吗?答:不能,做不到;

3.13兄弟之间也可以用管道,进行通信;爷爷和孙子也可以进行通信——使用管道通信,必须得是具有血缘关系;常用于父子之间

3.14 以上所说的文件,是在缓冲区中进行的,并不是在真实的文件中交互的,所以这个管道叫做匿名管道!

4.接口

4.1open、close是磁盘级的接口,不能用他,而是专用的接口pipe(系统接口)

 int pipe(int pipefd[2]);//pipdfd[2]  输出型参数
//pipefd[0]  只读下标 
//pipefd[1]  只写下标

4.2代码实现管道

// 实现系统间通信
#include <iostream>
#include <unistd.h>
#include <string>
#include <cstdlib> //stdlib.h C++风格的头文件写法
#include <sys/types.h>
#include <sys/wait.h>using namespace std;#defind N 2
#define NUM 1024
void Writer(int wfd)
{string s = "hello,i am child!";pid_t self = getpid();int number = 0;char buffer[NUM];while (true){//构建字符串buffer[0] = 0; // 字符串清空;只是为了提醒阅读代码的人,我把这个数组当作字符串了snprintf(buffer, sizeof(buffer), "%s-%d-%d", s.c_str(), self, number);//cout<<buffer<<endl;       //发送给父进程write(wfd,buffer,strlen(buffer));sleep(1);}
}
void Reader(int rfd)
{char buffer[NUM];while(true){buffer[0]=0;ssize_t n=read(rfd,buffer,sizeof(buffer));if(n>0){buffer[n]=0; //0=='\0'cout<<"father get a message["<<getpid()<<"]#"<<buffer<<endl;}}
}
int main()
{int pipefd[N] = {0};int n = pipe(pipefd); // 0下标是读;1下标是写if (n < 0){perror("pipe");return 1;}// cout<<"pipefd[0]:"<<pipefd[0]<<",pipefd[1]:"<<pipefd[1]<<endl;// 子进程写入,父进程读pid_t id = fork();if (id < 0)return 2;if (id == 0){// 子进程close(pipefd[0]);Writer(pipefd[1]);close(pipefd[1]);exit(0);}close(pipefd[1]);Reader(pipefd[1]);pid_t rid = waitpid(id, nullptr, 0);if (rid < 0)return 3;close(pipefd[0]);return 0;
}

4.3根据以上代码可以得到管道的本质:将上层缓冲区的数据拷贝到系统缓冲区,再将数据拷贝给上层缓冲区;

4.4进程间通信的本质:需要让不同的进程,看到同一份资源——但是是多执行流共享的,难免会出现访问冲突的问题;

5.管道的特征:五点

5.1具有血缘关系的进程进行进程间通信;

5.2管道只能单向通信;

5.3父子进程是会进程协同的,同步与互斥的——保护管道文件的数据安全;

5.4管道是面向字节流的;

5.5管道是基于文件的,文件的生命周期是跟随进程的(父子进程退出,管道会被操作系统回收)

6.管道的4种情况:

6.0管道是有大小的,Linux版本2.6.11之前是4KB,之后是64KB;(为了保障传输数据的整体性,有序性,定义了一个pipe_buf 大小是4KB,当写入系统缓冲区的数据小于4KB时,必须要等子进程传输完数据,父进程才能读——这个工作就是读取的原子性问题)

6.1读写端正常,管道如果为空,读端就要阻塞;

6.2读写端正常,管道如果被写满,写端就要阻塞

6.3读端正常,写端关闭,读端就会读到0,表明读到了文件(pipe)结尾,不会被阻塞;一直在读;

6.4读端关闭,写端正常,操作系统就要杀掉这个正在写入的进程;如何干掉?答:操作系统通过信号(是几号信号? 答:13号)干掉(操作系统是不会做低效,浪费等类似的工作的,如果做了,那就是操作系统的bug)

ulimit -a //查看系统对一些非常重要的资源的限制

7.管道的应用场景

7.1这个管道和我们以前学的知识,哪些是有关系的?

Linux shell 指令 :cat test.txt | head -10 |tail -5  这个语句的实现,就是shell命令+进程替换+管道实现的;

7.2使用管道实现一个简易版本的进程池;(请看下一节)

关键字:Linux 进程通信

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: