zoukankan      html  css  js  c++  java
  • Linux 进程间通信

    进程间通信的目的

    1. 数据交换
    2. 状态同步
    3. 事件通知
    4. 资源共享
    5. 进程控制

    一般来将进程之间的通信根据内容可以划分为两种,一种是传输控制信息,另一种是传输大量的数据。一般控制信息只有一个或几个字节,用来达到进程控制操作的高速执行(比如利用信号量实现进程同步);大量数据的传输一般用于进程之间信息的交换(CS架构中,客户端和服务器之间大量数据的交互)[4]。

    发展过程

    Linux中进程间通信(IPC)是从Unix中衍生过来的,最初的Unix具备管道、FIFO、信号,后来经过贝尔实验室和BSD(加州大学伯克利分校的伯克利软件发布中心)的拓展形成了现在的进程通信基础。

    贝尔实验室对早期的Unix进程通信方式进行了拓展,形成了“System V IPC”, 通信局限于单个计算机内;BSD打破了该限制,形成了基于套接字的进程间通信机制。而Linux将两者间的特色都继承了下来,同时它还兼容POSIX IPC标准(目前POSIX标准更加通用一些)。

    通信方式

    • 管道
    • 信号
    • 消息队列
    • 信号量
    • 共享内存
    • 套接字

    管道(Pipe)

    管道是Unix对操作系统的贡献之一,它是一个环形缓冲区,允许两个进程之间以生产者/消费者的模式进行通讯,是一个先进先出的队列[2]。

    管道是一种半双工的通信方式(消息只能单向传输)。数据传输方式似于流式传输,不提供随机访问,进程之间要约定一套数据协议来解析传输的数据[5]。数据由操作系统缓冲,直到接收方从中读取[1],它可以像文件描述符一样去通过select,poll和epoll函数去监听。

    管道在建立过程中需要双方进行协同操作(有些API中打开管道过程中会阻塞,直到双方都执行了打开操作),不能独立于进程而存在。

    管道分为匿名管道和命名管道(Named Pipe):匿名管道只有亲缘关系的进程(父进程与子进程之间,或子进程与子进程之间)可以共享;没有亲缘关系的进程之间只能通过命名管道通信。

    FIFO(first-in first-out special file, named pipe)在Linux中属于一种命名管道。通过绑定文件系统中指定文件来代替标准的输入输出[1],允许多个进程访问。

    Unix中对管道自动采取互斥保护措施,每次只有一个进程能访问管道[2]。

    信号(signal)

    信号是用于向一个进程通知某种事件的发生。除了进程间通信外还可以发送给进程本身。因为无法利用信号传输数据,所以信号主要用于进程管理上。

    Unix中内核平等的对待所有的信号,对于同时发生的信号,一次只给进程一个信号,而没有特定的顺序。进程间可以互相发送信号,内核在内部也可能发送信号[2]。

    我们经常使用的 Ctrl+C 就是发送一个退出的信号给某一进程。

    消息(Message)队列

    消息队列的功能类似于信箱,它也可以在没有亲缘关系的进程之间去使用,在双方没有直接连接的情况下进行通信[1]。消息队列是直接面对消息的,消息的发送者指定发送的消息的类型和大小,消息的接收者指定消息接收的方式(先进先出的规则或指定的消息类型)。

    克服了信号承载信息量少和管道只能承载无格式字节流的缺点,可以实现进程之间多对一的通信(C/S模式)。即使是接收者没有打开消息队列,发送者仍然可以打开队列发送消息而不阻塞,不需要额外的同步操作,可以避免管道中的打开和读写阻塞问题。

    消息队列中存储的消息数量是有上限的,同时每一条消息的大小也是有上限的。

    共享内存

    多个进程将同一个共享的内存段映射到自己的进程资源中,向同一段内存中读写数据来进行数据交互,是进程之间通信速度最快的一种方式,经常与其他通信机制(信号量)混合使用来达到进程间通信的目的[5]。

    Pipe和FIFO以及消息队列在交互信息的时候都需要通过内核拷贝的方式--将数据从发送方拷贝到内核缓存,再从内核缓存中拷贝到接收方[6],一次通信要COPY两次。而共享内存则不需要通过内核拷贝,所以速度上要比Pipe、FIFO和消息队列快一些。

    共享内存通常会在实时性要求比较高的业务情况下使用,比如金融系统中,但涉及到分布式的服务,经常需要跨主机的情况共享内存不太适合。

    套接字(Socket)

    常用于跨主机的进程通信,由BSD最早提供,后来被linux所吸收。它有通过网络端口跨主机通信的TCP/IP socket(面向流数据)和UDP socket(面向消息),也有UNIX domain socket这种只能在本地使用的类型。

    Unix domain socket 类似于TCP/IP互联网套接字,但所有通信都在内核中进行,使用文件系统作为其地址空间。进程做为inode来使用一个Unix domain socket,并且多个进程可以与同一个套接字进行通信(docker服务监听本地请求就是通过Unix domain socket)[1]。

    进程之间可以使用socket进行双向通信。

    信号量

    用于不同进程之间,或者同一进程中不同线程之间同步的通信机制。采用PV原语来实现。

    参考链接

  • 相关阅读:
    UVA 12697 Minimal Subarray Length
    学渣乱搞系列之后缀数组
    HDU 3518 Boring counting
    NYOJ 832 合并游戏
    如何在SAP里创建configurable material物料主数据
    在Kubernetes上运行SAP UI5应用(下): 一个例子体会Kubernetes内容器的高可用性和弹性伸缩
    使用SAP C4C rule editor动态控制UI上某个按钮是否显示
    ABAP SICF服务和Java Servlet的比较
    一些SAP Partners能够通过二次开发实现打通C/4HANA和S/4HANA的方法介绍
    Java实现的有道云笔记图片批量下载工具
  • 原文地址:https://www.cnblogs.com/cnblogs-wangzhipeng/p/9584956.html
Copyright © 2011-2022 走看看