进程间通信方式

news2024/9/29 15:31:27

每个进程的用户地址空间都是独立的,一般而言是不能互相访问的,但内核空间是每个进程都共享的,所以进程之间要通信必须通过内核。

管道

管道传输数据是单向的,如果想相互通信,我们需要创建两个管道才行。

|」表示的管道称为匿名管道,用完了就销毁。

对于匿名管道,它的通信范围是存在父子关系的进程。因为管道没有实体,也就是没有管道文件,只能通过 fork 来复制父进程 fd 文件描述符,来达到通信的目的。

另外,对于命名管道,它可以在不相关的进程间也能相互通信。因为命令管道,提前创建了一个类型为管道的设备文件,在进程里只要使用这个设备文件,就可以相互通信。

不管是匿名管道还是命名管道,进程写入的数据都是缓存在内核中,另一个进程读取数据时候自然也是从内核中获取,同时通信数据都遵循先进先出原则

消息队列

消息队列是保存在内核中的消息链表

消息队列生命周期随内核,如果没有释放消息队列或者没有关闭操作系统,消息队列会一直存在,而前面提到的匿名管道的生命周期,是随进程的创建而建立,随进程的结束而销毁。

消息这种模型,两个进程之间的通信就像平时发邮件一样,你来一封,我回一封,可以频繁沟通了。

但邮件的通信方式存在不足的地方有两点,一是通信不及时,二是附件也有大小限制,这同样也是消息队列通信不足的点。

消息队列不适合比较大数据的传输,因为在内核中每个消息体都有一个最大长度的限制,同时所有队列所包含的全部消息体的总长度也是有上限。在 Linux 内核中,会有两个宏定义 MSGMAX 和 MSGMNB,它们以字节为单位,分别定义了一条消息的最大长度和一个队列的最大长度。

消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销,因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。

共享内存

现代操作系统,对于内存管理,采用的是虚拟内存技术,也就是每个进程都有自己独立的虚拟内存空间,不同进程的虚拟内存映射到不同的物理内存中。共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。这样这个进程写入的东西,另外一个进程马上就能看到了,都不需要拷贝来拷贝去,传来传去,大大提高了进程间通信的速度。

信号量

用了共享内存通信方式,带来新的问题,那就是如果多个进程同时修改同一个共享内存,很有可能就冲突了。例如两个进程都同时写一个地址,那先写的那个进程会发现内容被别人覆盖了。

为了防止多进程竞争共享资源,而造成的数据错乱,所以需要保护机制,使得共享的资源,在任意时刻只能被一个进程访问。正好,信号量就实现了这一保护机制。

信号量其实是一个整型的计数器,主要用于实现进程间的互斥与同步,而不是用于缓存进程间通信的数据

信号量表示资源的数量,控制信号量的方式有两种原子操作:

  • 一个是 P 操作,这个操作会把信号量减去 1,相减后如果信号量 < 0,则表明资源已被占用,进程需阻塞等待;相减后如果信号量 >= 0,则表明还有资源可使用,进程可正常继续执行。
  • 另一个是 V 操作,这个操作会把信号量加上 1,相加后如果信号量 <= 0,则表明当前有阻塞中的进程,于是会将该进程唤醒运行;相加后如果信号量 > 0,则表明当前没有阻塞中的进程;

P 操作是用在进入共享资源之前,V 操作是用在离开共享资源之后,这两个操作是必须成对出现的。

可以发现,信号初始化为 1,就代表着是互斥信号量,它可以保证共享内存在任何时刻只有一个进程在访问,这就很好的保护了共享内存。

可以发现,信号初始化为 0,就代表着是同步信号量,它可以保证进程 A 应在进程 B 之前执行。

信号量不仅可以实现临界区的互斥访问控制,还可以线程间的事件同步。

我们先来说说如何使用信号量实现临界区的互斥访问

为每类共享资源设置一个信号量 s,其初值为 1,表示该临界资源未被占用。

只要把进入临界区的操作置于 P(s) 和 V(s) 之间,即可实现进程/线程互斥:

此时,任何想进入临界区的线程,必先在互斥信号量上执行 P 操作,在完成对临界资源的访问后再执行 V 操作。由于互斥信号量的初始值为 1,故在第一个线程执行 P 操作后 s 值变为 0,表示临界资源为空闲,可分配给该线程,使之进入临界区。

若此时又有第二个线程想进入临界区,也应先执行 P 操作,结果使 s 变为负值,这就意味着临界资源已被占用,因此,第二个线程被阻塞。

并且,直到第一个线程执行 V 操作,释放临界资源而恢复 s 值为 0 后,才唤醒第二个线程,使之进入临界区,待它完成临界资源的访问后,又执行 V 操作,使 s 恢复到初始值 1。

对于两个并发线程,互斥信号量的值仅取 1、0 和 -1 三个值,分别表示:

  • 如果互斥信号量为 1,表示没有线程进入临界区;
  • 如果互斥信号量为 0,表示有一个线程进入临界区;
  • 如果互斥信号量为 -1,表示一个线程进入临界区,另一个线程等待进入。

通过互斥信号量的方式,就能保证临界区任何时刻只有一个线程在执行,就达到了互斥的效果。

信号

上面说的进程间通信,都是常规状态下的工作模式。对于异常情况下的工作模式,就需要用「信号」的方式来通知进程。

信号跟信号量虽然名字相似度 66.66%,但两者用途完全不一样

信号事件的来源主要有硬件来源(如键盘 Cltr+C )和软件来源(如 kill 命令)

进程间通信机制中唯一的异步通信机制,因为可以在任何时候发送信号给某一进程,一旦有信号产生,我们就有下面这几种,用户进程对信号的处理方式。

1.执行默认操作。Linux 对每种信号都规定了默认操作,例如,上面列表中的 SIGTERM 信号,就是终止进程的意思。

2.捕捉信号。我们可以为信号定义一个信号处理函数。当信号发生时,我们就执行相应的信号处理函数。

3.忽略信号。当我们不希望处理某些信号的时候,就可以忽略该信号,不做任何处理。有两个信号是应用进程无法捕捉和忽略的,即 SIGKILL 和 SEGSTOP,它们用于在任何时候中断或结束某一进程

Socket

前面提到的管道、消息队列、共享内存、信号量和信号都是在同一台主机上进行进程间通信,那要想跨网络与不同主机上的进程之间通信,就需要 Socket 通信了。

Socket 通信不仅可以跨网络与不同主机的进程间通信,还可以在同主机上进程间通信。

我们来看看创建 socket 的系统调用:

三个参数分别代表:

  • domain 参数用来指定协议族,比如 AF_INET 用于 IPV4、AF_INET6 用于 IPV6、AF_LOCAL/AF_UNIX 用于本机;
  • type 参数用来指定通信特性,比如 SOCK_STREAM 表示的是字节流,对应 TCP、SOCK_DGRAM 表示的是数据报,对应 UDP、SOCK_RAW 表示的是原始套接字;
  • protocal 参数原本是用来指定通信协议的,但现在基本废弃。因为协议已经通过前面两个参数指定完成,protocol 目前一般写成 0 即可;

根据创建 socket 类型的不同,通信的方式也就不同:

  • 实现 TCP 字节流通信: socket 类型是 AF_INET 和 SOCK_STREAM;
  • 实现 UDP 数据报通信:socket 类型是 AF_INET 和 SOCK_DGRAM;
  • 实现本地进程间通信: 「本地字节流 socket 」类型是 AF_LOCAL 和 SOCK_STREAM,「本地数据报 socket 」类型是 AF_LOCAL 和 SOCK_DGRAM。另外,AF_UNIX 和 AF_LOCAL 是等价的,所以 AF_UNIX 也属于本地 socket;

针对 TCP 协议通信的 socket 编程模型

  • 服务端和客户端初始化 socket,得到文件描述符;
  • 服务端调用 bind,将绑定在 IP 地址和端口;
  • 服务端调用 listen,进行监听;
  • 服务端调用 accept,等待客户端连接;
  • 客户端调用 connect,向服务器端的地址和端口发起连接请求;
  • 服务端 accept 返回用于传输的 socket 的文件描述符;
  • 客户端调用 write 写入数据;服务端调用 read 读取数据;
  • 客户端断开连接时,会调用 close,那么服务端 read 读取数据的时候,就会读取到了 EOF,待处理完数据后,服务端调用 close,表示连接关闭。

这里需要注意的是,服务端调用 accept 时,连接成功了会返回一个已完成连接的 socket,后续用来传输数据。

所以,监听的 socket 和真正用来传送数据的 socket,是「两个」 socket,一个叫作监听 socket,一个叫作已完成连接 socket

成功连接建立之后,双方开始通过 read 和 write 函数来读写数据,就像往一个文件流里面写东西一样。

针对 UDP 协议通信的 socket 编程模型

UDP 是没有连接的,所以不需要三次握手,也就不需要像 TCP 调用 listen 和 connect,但是 UDP 的交互仍然需要 IP 地址和端口号,因此也需要 bind。

对于 UDP 来说,不需要要维护连接,那么也就没有所谓的发送方和接收方,甚至都不存在客户端和服务端的概念,只要有一个 socket 多台机器就可以任意通信,因此每一个 UDP 的 socket 都需要 bind。

另外,每次通信时,调用 sendto 和 recvfrom,都要传入目标主机的 IP 地址和端口。

针对本地进程间通信的 socket 编程模型

本地 socket 被用于在同一台主机上进程间通信的场景:

  • 本地 socket 的编程接口和 IPv4 、IPv6 套接字编程接口是一致的,可以支持「字节流」和「数据报」两种协议;
  • 本地 socket 的实现效率大大高于 IPv4 和 IPv6 的字节流、数据报 socket 实现;

对于本地字节流 socket,其 socket 类型是 AF_LOCAL 和 SOCK_STREAM。

对于本地数据报 socket,其 socket 类型是 AF_LOCAL 和 SOCK_DGRAM。

本地字节流 socket 和 本地数据报 socket 在 bind 的时候,不像 TCP 和 UDP 要绑定 IP 地址和端口,而是绑定一个本地文件,这也就是它们之间的最大区别。

以上,就是进程间通信的主要机制了。你可能会问了,那线程通信间的方式呢?

同个进程下的线程之间都是共享进程的资源,只要是共享变量都可以做到线程间通信,比如全局变量,所以对于线程间关注的不是通信方式,而是关注多线程竞争共享资源的问题,信号量也同样可以在线程间实现互斥与同步:

  • 互斥的方式,可保证任意时刻只有一个线程访问共享资源;
  • 同步的方式,可保证线程 A 应在线程 B 之前执行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/429485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端引入和html标签

先安装 flask模块 pip install flask from flask import Flaskapp Flask(__name__)#创建了网址 /show/info 和函数index的对应关系 #以后用户在浏览器上访问 /show/info&#xff0c;网站自动执行 index app.route("/show/info") def index():return "西安钟楼…

Vivado自带仿真器:真的不好用吗?

Vivado仿真器不好用&#xff1f;如果你还不熟悉它的操作方法&#xff0c;可能会有这种感觉。 实际上&#xff0c;与ModelsIm相比&#xff0c;Vivado仿真器的仿真速度稍慢&#xff0c;但是它的界面美观整洁&#xff0c;操作丰富且流畅&#xff0c;特别适合于调试仿真时间短的工…

JUC高级九-Synchronized与锁升级

1. synchronized 锁优化的背景 用锁能够实现数据的安全性&#xff0c;但是会带来性能下降。无锁能够基于线程并行提升程序性能&#xff0c;但是会带来安全性下降。 为求平衡将synchronized优化为不在是无所和重锁两个状态,新增偏向锁和轻量级锁来平衡安全性和性能问题 synchro…

【一起啃书】《机器学习》第四章决策树

第四章 决策树 4.1 基本流程 决策树是一类常见的机器学习方法&#xff0c;是基于树结构来进行决策的&#xff0c;通过对训练样本的分析来确定划分属性&#xff0c;来模拟人类决策过程。 一般的&#xff0c;一棵决策树包含一个根结点、若干个内部结点和若干个叶结点&#xff0c;…

分页查询工具类

package xyz.huanggy.minio.upload.Util; import java.util.ArrayList; import java.util.List; public class PageBean<T> {/*** 功能&#xff1a;分页工具类*/private int pageSize; // 每页记录数private int pageNo; // 当前页private int totalPages; // 总页数priv…

【Redis】Lua快速入门使用

【Redis】Lua快速入门使用 文章目录【Redis】Lua快速入门使用1. 概述2. 数据类型2.1 变量2.2 循环3. 函数4. 条件控制1. 概述 Lua 是一种轻量小巧的脚本语言&#xff0c;用标准C语言编写并以源代码形式开放&#xff0c; 其设计目的是为了嵌入应用程序中&#xff0c;从而为应用…

vue+Nodejs+Koa搭建前后端系统(二)--koa-generator创建项目及分析

前言 采用上一篇vueNodejsKoa搭建前后端系统&#xff08;一&#xff09;–简易版创建的项目目录的基础上&#xff0c;创建新的后端服务项目server2使用koa-generator脚手架创建后端项目计算机系统为Windows 10 专业版 小说中&#xff0c;终成眷属一般就结局了&#xff0c;但现…

ESP32在ESP-IDF框架下为LVGL(v8.3)配置SD卡文件系统

踩坑记录 1、如果SD卡曾经做过系统盘&#xff08;比如说&#xff1a;作为树莓派的系统盘&#xff09;&#xff0c;那么要把系统盘的分区合并成一个&#xff08;这个网上有很多教程&#xff09;&#xff0c;并重新格式化&#xff0c;否则实验会失败。 2、并不是买回来的新的SD卡…

基于Vant组件库二次封装组件(TS+Vue3.x环境)

1. 今天的需求是封装一个 Navigation Bar 导航栏组件&#xff0c;目的是给到App几乎所有的页面复用&#xff1a; 2. 因为之前的项目里使用过Vant组件库&#xff0c;笔者第一时间想到了Vant组件库中的 NavBar 组件&#xff0c;和当前App的需求匹配度很高。Vant组件库的 NavBar 组…

压箱底教程分享,手把手教会你如何注册target账号和下单

喜欢套利的朋友肯定都认识target这个平台吧&#xff0c;它是美国热门的综合性海淘网站之一。东哥近日收到私信有朋友向我请教在注册target账号时遇到的一些问题&#xff0c;所以今天东哥想跟大家分享的就是就是target账号注册教程和下单流程&#xff0c;让也想注册target账号的…

软考第五章 无线通信网

无线通信网 无线通信网包括面向语音通信的移动电话系统以及面向数据传输的无线局域网和无线广域网。 WiFI底层是如何传输数据的呢 1.移动通信 1.1 蜂窝通信系统 1980年中期&#xff0c;欧洲和日本都建立了第一代蜂窝移动电话系统。蜂窝网络把一个地理区域划分成若干个称为…

Vue2-黑马(五)

目录&#xff1a; &#xff08;1&#xff09;vue2-组件重用 &#xff08;2&#xff09;vue2-element ui安装 &#xff08;3&#xff09;vue2-ElementUI-table &#xff08;4&#xff09;Element-ui-分页pagination &#xff08;1&#xff09;vue2-组件重用 页面上有很多的…

PyTorch中的符号索引和函数索引用法

Pytorch中很多函数都采用的是函数式索引的思路&#xff0c;而且使用函数式索引对代码可读性会有很大提升。 张量的符号索引 张量也是有序序列&#xff0c;我们可以根据每个元素在系统内的顺序位置&#xff0c;来找出特定的元素&#xff0c;也就是索引。 一维张量的索引 一维…

离线安装JumpServer

官网操作手册&#xff1a; https://docs.jumpserver.org/zh/v3/installation/setup_linux_standalone/offline_install/ 环境要求&#xff1a;&#xff08;内存最小需要4G&#xff09; 架构图 安装部署 1、下载 JumpServer官网下载&#xff1a; https://community.fit2cloud…

定点数的二进制表示形式

定点数的二进制表示形式 文章目录定点数的二进制表示形式什么是定点数表示格式数值范围与分辨率转换python 转换定点数C 双精度浮点数转换为8位和16位定点数C 将定点数转回浮点数测试什么是定点数 在嵌入式系统中&#xff0c;为了降低运算复杂度&#xff0c;通常还会使用定点数…

有趣的数学之回文数

“回文”是指正读反读都能读通的句子&#xff0c;它是古今中外都有的一种修辞方式和文字游戏&#xff0c;如“我为人人&#xff0c;人人为我”等&#xff0c;最有名的莫过于“上海自来水来自海上&#xff0c;人过大佛寺佛大过人 ”。你们知道吗&#xff0c;在数学中也有这样一类…

30多份软件测试报告模板,如何写一份优秀测试报告模板流程

相信很多做软件测试的小伙伴在软件测试后期&#xff0c;都为软件测试报告总结花费了很多的精力&#xff0c;那么如何做好软件测试报告呢&#xff1f;一份优秀的测试报告又包含哪些内容呢&#xff1f; 测试报告的核心要素 一、测试结论 从测试工程师的专业角度分析&#xff0…

pytorch进阶学习(四):使用不同分类模型进行数据训练(alexnet、resnet、vgg等)

课程资源&#xff1a;5、帮各位写好了十多个分类模型&#xff0c;直接运行即可【小学生都会的Pytorch】_哔哩哔哩_bilibili 目录 一、项目介绍 1. 数据集准备 2. 运行CreateDataset.py 3. 运行TrainModal.py 4. 如何切换显卡型号 二、代码 1. CreateDataset.py 2.Train…

如何基于ChatGPT+Avatar搭建24小时无人直播间

0 前言 最近朋友圈以及身边很多朋友都在研究GPT开发&#xff0c;做了各种各样的小工具小Demo&#xff0c;AI工具用起来是真的香&#xff01;在他们的影响下&#xff0c;我也继续捣鼓GPT Demo&#xff0c;希望更多的开发者加入一起多多交流。 上一篇结合即时通 IM SDK捣鼓了一个…

因为这三个面试题,我与字节offer失之交臂

我一个朋友挑战3个月入职字节&#xff0c;一路过关斩将直到终面&#xff0c;着实把我惊了一把&#xff0c;可惜的是&#xff0c;他倒在了最后三个面试题上。 我很讶异&#xff0c;前面不是打得很好吗&#xff1f;怎么会在最后几题上犯错误呢&#xff1f; 朋友说&#xff1a;别…