为Linux应用程序的开发人员,对Linux的进程间通信方式肯定是了如指掌,平时的开发中应该会大量的使用到。当你迅速的在键盘上按下【CTRL+C】终止掉一个正在运行中的命令时,你有没有仔细的思考过背后的原理呢?或者是他们是通过什么通信方式呢?这个通信方式是怎样实现的呢?本文就带着大家去Linux进程间通信一探究竟,找出他们的原理。

概念

我们都知道,应用程序在运行起来之后(进程),是相互独立的,都有自己的进程地址空间。但是往往在一些业务上需要进程间的通信,来完成系统的某个完整的功能。我们来看下进程间通信能干那些事情?首先当然最重要的是:

  1. 数据传输。一个进程需要发送数据到另一个进程,这种需求肯定是存在的。
  2. 共享数据。如果有多个进程想要访问数据,一个进程修改了内容,另一个进程能够立即看到内容变化。
  3. 资源保护:上面的的操作中存在竞争情况,内核需要提供锁和同步机制。
  4. 通知:一个进程需要向另一个进程发送消息,通知发生了某个事件。
  5. 控制:有些进程需要控制另一个进程的运行。典型的例子就是gdb,可参考之前文章【gdb到底是怎么实现的?】

通信方式

进程间的通信方式一般可以分为八种,如下:

八种通信方式

他们在不同的标准都有不同的实现,如下图所示:

通信方式框图

我们先从管道开始讲起来吧。

管道

这里说的管理特指的是无名管道,它是一种半双工的通信方式。也就是说数据只能单向流动,一般是在具有亲缘关系的进程间使用,比如父子进程。当一个进程创建了一个管道,并调用fork创建自己的一个子进程后,父进程关闭读管道端,子进程关闭写管道端,这样提供了两个进程之间数据流动的一种方式。

管道是怎么通信的呢?

首先管道是内核的一个缓冲区,而且是在内存中。管道一头连接着一个进程的输出,另一头连接着另一个进程的输入。一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管道可以被循环利用。当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的时候,管道也自动消失。看下图:

那管道怎样建立的呢?

从原理上,管道利用fork机制建立,从而让两个进程可以连接到同一个PIPE上。最开始的时候,上面的两个箭头都连接在同一个进程1上(连接在进程1上的两个箭头),如下图。当fork复制进程的时候,会将这两个连接也复制到新的进程(进程2)。随后,每个进程关闭自己不需要的一个连接 (两个黑色的箭头被关闭; 进程1关闭从PIPE来的输入连接,进程2关闭输出到PIPE的连接),这样,剩下的红色连接就构成了如上图的PIPE。

管道在内核中具体怎么实现的呢?

在Linux内核中,并没有针对管道新增数据结构。而是巧妙的借用了文件系统的file结构和虚拟文件系统的索引节点inode。通过将两个 file 结构指向同一个临时的 VFS 索引节点,而这个 VFS 索引节点又指向一个物理页面而实现的。

具体实现

管道的实现其实也不难,源代码在内核工程中的fs/pipe.c,我们着重的讲两个比较重要的接口吧,也就是常用的pipe_read()和pipe_write(),前者是管道读函数,后者是管道写函数。

管道写函数将字节数据复制到虚拟文件系统索引节点指向的物理内存页,而读函数则是相反:读出数据。当然这里存在着竞争的管理,需要一定的同步机制,使用锁,等待队列和信号。

当我们写的时候,调用write(),内核根据传入的文件描述符fd,找到该文件的file结构。然后执行结构中f_op中的写函数。写函数在向内存写入数据之前,必须首先检查虚拟文件系统索引节点信息,检查是否有足够的内存空间可以写和内存没有被读程序锁定这两个条件,只有满足了,才真正的进行内存拷贝。

接下来写函数就会锁定内存,然后复制数据到内存,否则就在虚拟文件系统inode的等待队列中。

管道的读取过程和写入过程类似。但是,进程可以在没有数据或内存被锁定时立即返回错误信息,而不是阻塞该进程,这依赖于文件或管道的打开模式。反之,进程可以休眠在索引节点的等待队列中等待写入进程写入数据。当所有的进程完成了管道操作之后,管道的索引节点被丢弃,而共享数据页也被释放。

总结

由于篇幅的限制,八大进程间通信只讲了管道,文章开头的疑问也只能等到后续文章了,也算是留个悬念吧。

图解Linux进程间通信实现原理(1)的更多相关文章

  1. Linux进程间通信(五):信号量 semget()、semop()、semctl()

    这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信 -- 信号.下面 ...

  2. Linux进程间通信——使用信号量

    这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...

  3. c/c++ linux 进程间通信系列5,使用信号量

    linux 进程间通信系列5,使用信号量 信号量的工作原理: 由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的: P(sv):如果sv的值大于零,就给它减1:如果 ...

  4. Linux进程间通信--使用信号量【转】

    本文转载自:http://blog.csdn.net/ljianhui/article/details/10243617 这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号 ...

  5. Linux进程间通信——使用信号量(转)

    这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...

  6. Linux进程间通信—管道

    Linux下的进程通信手段基本上是从UNIX平台上的进程通信手段继承而来的.而对UNIX发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...

  7. Linux进程间通信——使用信号量【转】

    本文转载自:http://blog.csdn.net/ljianhui/article/details/10243617 这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号 ...

  8. [转载]Linux Bond的原理及其不足

    本文转自http://www.yunweipai.com/archives/1969.html 支持原创.尊重原创,分享知识! 在企业及电信Linux服务器环境上,网络配置都会使用Bonding技术做 ...

  9. Linux进程间通信(一): 信号 signal()、sigaction()

    一.什么是信号 用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中 ...

随机推荐

  1. VisualSVN 关于权限(第2篇)

    最终的答案: 仓库本身不能给他增加访问权限,必须增加否则连不上,不增加的时候 他默认就是No Access: 仓库本身可以理解为:祖宗,他是访问权限的根基.子目录会继承他的权限. 那么既然必须给他增加 ...

  2. springboot启动流程(一)构造SpringApplication实例对象

    所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 启动入口 本文是springboot启动流程的第一篇,涉及的内容是SpringApplicat ...

  3. React实现顶部固定滑动式导航栏(导航条下拉一定像素时显示原导航栏样式)

    摘要 基于react的框架开发一个顶部固定滑动式的酷炫导航栏,当导航栏置顶时,导航栏沉浸在背景图片里:当鼠标滑动滚轮时,导航栏固定滑动并展示下拉样式. JS部分 相关技术栈:react.antd.re ...

  4. B+树Java代码实现以及测试

    M阶B+树的定义: 任意非叶子结点最多有M个子节点:且M>2: 除根结点以外的非叶子结点至少有 M/2个子节点: 根结点至少有2个子节点: 除根节点外每个结点存放至少M/2和至多M个关键字:(至 ...

  5. Spring中Bean的管理问题

    首先,配置文件中定义的bean并不是都在启动时实例化. <bean id="accountService" class="com.foo.DefaultAccoun ...

  6. javascript实现Html Table数据表分页

    直接调用: <style type="text/css">           th         {             font-size:18px;     ...

  7. 使用raw input 代替全局键盘钩子

    //关于raw input 请查看msdn https://msdn.microsoft.com/en-us/library/windows/desktop/ms645536%28v=vs.85%29 ...

  8. 玩深度学习选哪块英伟达 GPU?有性价比排名还不够!

    本文來源地址:https://www.leiphone.com/news/201705/uo3MgYrFxgdyTRGR.html 与“传统” AI 算法相比,深度学习(DL)的计算性能要求,可以说完 ...

  9. [ 转载 ] Java基础

    1.String a = “123”; String b = “123”; a==b的结果是什么? 这包含了内存,String存储方式等诸多知识点.ans:同样序列的字符串直接量为一个实例,所以其实引 ...

  10. [原创]VSCode debug jest的配置

    重拾JS的路从修改JS源码开始,修改JS源码从源码自带的test code开始.源码的test code使用了jtest框架,从test code刚好可以看到要修改部分的 多种传值方式,以及函数输出结 ...