Linux 进程 | 进程间的通信方式

文章目录

  • 管道
    • 匿名管道 pipe
    • 命名管道 FIFO
  • 共享内存
    • 共享内存的使用流程:
  • 消息队列
  • 信号量
  • 套接字


在之前的博客中讲过,虚拟空间出现的其中一个目的就是解决 进程没有独立性,可能访问同一块物理内存 的问题。因为这种独立性,进程之间无法直接进行通信,操作系统为了解决这种问题,提出了多种适用于不同情境下的通信方式:

  • 数据传输:管道、消息队列
  • 数据共享:共享内存
  • 进程控制:信号量

管道

管道的本质其实就是内核中的一块缓冲区,多个进程通过访问同一个缓冲区就可以实现进程间的通信。自 Linux 2.6.11 内核起,管道容量的大小默认是 65536 字节,但可以通过 fcntl函数 来修改管道容量。

在这里插入图片描述

管道分为两种:匿名管道、命名管道


匿名管道 pipe

因为没有具体的文件描述符,所以只能用于具有亲缘(父子)关系的进程之间的通信。

原理: 父进程在创建管道的时候操作系统会返回管道的文件描述符,然后生成子进程时子进程会通过拷贝父进程的 pcb 来获取到这个管道的描述符,所以他们可以通过这个文件描述符来访问同一个管道,来实现进程间的通信。而不具备亲缘关系的进程则无法通过这个文件描述符来访问同一个管道。

在这里插入图片描述
返回值:成功返回 0,失败返回 -1

在这里插入图片描述
也就是说读/写操作的流程是:

  1. 关闭 读/写 端
  2. 进行 写/读 操作
  3. 写/读 完关闭 写/读 端

图解父子进程通过管道通信的流程:

一开始父进程创建管道
在这里插入图片描述
父进程fork创建子进程

在这里插入图片描述

关闭多余描述符

在这里插入图片描述
代码示例:示例一 示例二

如果没有特意规定,那么父子进程究竟是谁先执行是不确定的,假设如果子进程还没写入,父进程却已经开始读了,这时候应该是会读不到东西的,会在屏幕上输出空行,但是这种情况并没有发生,这里就牵扯到了管道的读写特性:

  • 如果管道中没有数据,则调用 read 读取数据会阻塞。
  • 如果管道中数据满了,则调用 write 写入数据会阻塞。
  • 如果管道的所有 读端 被关闭,继续调用 write 时,会因为无法读出而产生异常导致进程退出。
  • 如果管道的所有 写端 被关闭,继续调用 read 时,read 读完管道中的所有数据后不再阻塞,返回 0 退出。

命名管道 FIFO

命名管道也是内核中的一块缓冲区,但是它 具有标识符 。这个标识符是一个可见于文件系统的管道文件,能够被其他进程找到并打开管道文件来获取管道的操作句柄,多个进程可以通过打开这个管道文件来访问同一块缓冲区来实现通信。

  • 可以在没有亲缘关系(非父子)的进程之间进行通信,这是与无名管道最大的区别。
  • 他是以一个特性的文件存储在文件系统中, 所以对他的操作与其路径名有关联。

接口:

int mkfifo(const char *filename,mode_t mode);

filename——管道的标识符,通过这个标识符来访问管道,创建之前这个标识符必须不存在。
mode——权限掩码。
返回值——若成功则返回 0,否则返回 -1

代码示例: 命名管道实现进程的信息传递【mkfifo函数、open函数】

open 打开命名管道的特性:

  1. 若文件以只读打开,则会阻塞,直到文件被以写的方式打开。
  2. 若文件以只写打开,则会阻塞,直到文件被以读的方式打开。

管道的特性:

  1. 管道是半双工通信(可以选择方向的单向传输),这个可以从上面的示意图看出来。
  2. 管道的读写特性(无论命名匿名都一样)。
  3. 管道声明周期随进程,打开管道的所有进程退出后管道就会被释放。
  4. 管道提供字节流传输服务。
  5. 命名管道额外有一个打开特性,只读打开会阻塞直到被以写打开,只写打开会阻塞直到被以读打开。
  6. 管道自带同步和互斥。

共享内存

共享内存即在 物理内存 上开辟一块空间,然后 多个进程 通过 页表 将这 同一个物理内存 映射到自己的 虚拟地址空间 中,通过自己的 虚拟地址空间 来访问这块 物理内存 ,达到了数据共享的目的。

在这里插入图片描述
也正是因为这种特性,使得 共享内存成为了最快的进程间通信的方式 ,因为它 直接通过虚拟地址来访问物理内存,比前面的管道和后面的消息队列 少了内核态和用户态的几次数据拷贝和交互

特点:

  1. 生命周期随内核。
  2. 由于多个进程可以同时操作,因此需要进行同步。但不自带同步与互斥,而是借助信号量来实现同步与互斥。

共享内存的使用流程:

1. 创建共享内存

头文件:
#include <sys/ipc.h>
#include <sys/shm.h>
定义函数:
int shmget(key_t key, size_t size, int shmflg)
参数:
key:这个共享内存段名字
size:共享内存大小
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的。返回值:成功返回共享内存标识符,失败返回-1

2. 将共享内存映射到虚拟地址空间

头文件:
#include <sys/types.h>
#include <sys/shm.h>
定义函数:
void *shmat(int shmid, const void *shmaddr, int shmflg)
参数:
shmid: 共享内存标识
shmaddr:指定连接的地址
shmflg:权限标志返回值:成功返回指向共享内存映射在虚拟地址空间的指针(即首地址),失败返回-1

3. 共享内存管理

头文件:
#include <sys/types.h>
#include <sys/shm.h>
定义函数:
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
参数:
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构返回值:成功返回0,失败返回-1

4. 解除映射关系

头文件:
#include <sys/types.h>
#include <sys/shm.h>
定义函数:
int shmdt(const void *shmaddr)
参数:shmaddr: 由shmat所返回的指针
返回值:成功返回0,失败返回-1

消息队列

概念:

  1. 消息队列是内核中的一个优先级队列,多个进程通过访问同一个队列,进行添加节点或者获取节点来实现通信。
  2. 消息队列是消息的连接表, 放在内核中, 一个消息队列由一个标识符表示。
  3. 消息队列是面向记录的, 其中的消息具有特定的格式以及特定的优先级。
  4. 消息队列独立于发送和接受进程中, 也就是当一个进程被销毁, 他在消息队列中的信息是不会被删除的。
  5. 消息队列中的内容可以实现随机查询, 也就是消息不一定要以 FIFO 读取, 也可以按消息的类型读取。

特性:

  • 自带同步与互斥
  • 生命周期随内核

流程:

1. 创建消息队列

头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定义函数:
int msgget(key_t key, int msgflg)
参数:
key:消息队列对象的关键字
msgflg:消息队列的建立标志和存取权限返回值:成功执行时,返回消息队列标识值。失败返回-1

2. 进程可以向队列中添加/获取节点

头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
添加节点:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
获取节点:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数:
msqid:消息队列对象的标识符
msgp:消息缓冲区指针
msgsz:消息数据的长度
msgtyp:决定从队列中返回哪条消息
msgflg:消息队列状态返回值:成功执行时,返回0。失败返回-1

3. 删除消息队列

头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
定义函数:
int msgctl(int msqid, int cmd, struct msqid_ds *buf)
参数:
msqid:消息队列对象的标识符
cmd:函数要对消息队列进行的操作
buf:取出系统保存的消息队列的 msqid_ds 数据,并将其存入参数 buf 指向的 msqid_ds 结构中返回值:成功执行时,返回0。失败返回-1

信号量

概念:

  • 信号量与IPC结构不同,它其实是 内核中的一个计数器和阻塞队列 ,通过信号量来对 临界资源的访问进行控制,来 实现进程间的同步与互斥 ,而不是用于进程间消息的通信的。
  • 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
  • 信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
  • 每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。

例如:有一个能容纳 n 人的餐厅,用一个计数器表示 n,如果有人进入则 n - 1,如果有人出来则 n + 1,只有 n > 0 时才能进入,如果 n <= 0 时,则说明没有位置,需要将进程挂起并放入阻塞队列中,直到有人出来使资源释放时,才能将后续进程从阻塞队列中唤醒获取资源。

  • 同步:通过条件判断实现临界资源访问的合理性
  • 互斥:通过同一时间的唯一访问来实现临界资源访问的安全性

POSIX信号量: POSIX 信号量和 SystemV 信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但 POSIX 可以用于线程间同步。

流程:

#include <semaphore.h>//初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
/*
参数:
pshared:0表示线程间共享,非零表示进程间共享
value:信号量初值
*///销毁信号量
int sem_destroy(sem_t *sem);//等待信号量
int sem_wait(sem_t *sem);
//功能:等待信号量,会将信号量的值减1//发布信号量
int sem_post(sem_t *sem);
//功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。

套接字

使用套接字也可以实现进程间的通信,与其他机制不同的是,它可以实现不同机器之前的进程间的通信。

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

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

相关文章

Linux网络编程 | socket介绍、网络字节序与主机字节序概念与两者的转换、TCP/UDP 连接中常用的 socket 接口

文章目录套接字socket 地址通用 socket 地址专用 socket 地址网络字节序与主机字节序地址转换TCP/UDP 连接中常用的 socket 接口套接字 什么是套接字&#xff1f; 所谓 套接字 (Socket) &#xff0c;就是对网络中 不同主机 上的应用进程之间进行双向通信的端点的抽象。 UNIX/L…

网络协议分析 | 传输层 :史上最全UDP、TCP协议详解,一篇通~

文章目录UDP概念格式UDP如何实现可靠传输基于UDP的应用层知名协议TCP概念格式保证TCP可靠性的八种机制确认应答、延时应答与捎带应答超时重传滑动窗口滑动窗口协议后退n协议选择重传协议流量控制拥塞控制发送窗口、接收窗口、拥塞窗口快速重传和快速恢复连接管理机制三次握手连…

JDom,jdom解析xml文件

1.要解析的文件模板如下&#xff1a; <?xml version"1.0" encoding"GBK"?> <crsc> <data><举报信息反馈><R index"1"><举报编号>1</举报编号><状态>1</状态><答复意见>填写…

网络协议分析 | 应用层:HTTP协议详解、HTTP代理服务器

文章目录概念URLHTTP协议的特点HTTP协议版本格式请求报文首行头部空行正文响应报文首行头部空行正文Cookie与SessionHTTP代理服务器正向代理服务器反向代理服务器透明代理服务器概念 先了解一下 因特网&#xff08;Internet&#xff09; 与 万维网&#xff08;World Wide Web&…

MySQL命令(一)| 数据类型、常用命令一览、库的操作、表的操作

文章目录数据类型数值类型字符串类型日期/时间类型常用命令一览库的操作显示当前数据库创建数据库使用数据库删除数据库表的操作创建表显示当前库中所有表查看表结构删除表数据类型 mysql 的数据类型主要分为 数值类型、日期/时间类型、字符串类型 三种。 数值类型 数值类型可…

C++ 继承 | 对象切割、菱形继承、虚继承、对象组合

文章目录继承继承的概念继承方式及权限using改变成员的访问权限基类与派生类的赋值转换回避虚函数机制派生类的默认成员函数友元与静态成员多继承菱形继承虚继承组合继承 继承的概念 继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。 当创建一个类时&…

博弈论 | 博弈论简谈、常见的博弈定律、巴什博弈

文章目录博弈论什么是博弈论&#xff1f;博弈的前提博弈的要素博弈的分类非合作博弈——有限两人博弈囚徒困境合作博弈——无限多人博弈囚徒困境常见的博弈定律零和博弈重复博弈智猪博弈斗鸡博弈猎鹿博弈蜈蚣博弈酒吧博弈枪手博弈警匪博弈海盗分金巴什博弈博弈论 什么是博弈论…

MySQL命令(二)| 表的增删查改、聚合函数(复合函数)、联合查询

文章目录新增 (Create)全列插入指定列插入查询 (Retrieve)全列查询指定列查询条件查询关系元素运算符模糊查询分页查询去重&#xff1a;DISTINCT别名&#xff1a;AS升序 or 降序更新 (Update)删除 (Delete)分组&#xff08;GROUP BY&#xff09;联合查询内连接&#xff08;inne…

MySQL | 数据库的六种约束、表的关系、三大范式

文章目录数据库约束NOT NULL&#xff08;非空约束&#xff09;UNIQUE&#xff08;唯一约束&#xff09;DEFAULT&#xff08;缺省约束&#xff09;PRIMARY KEY&#xff08;主键约束&#xff09;AUTO_INCREMENT 自增FOREIGN KEY&#xff08;外键约束&#xff09;CHECK&#xff08…

哈希 :哈希冲突、负载因子、哈希函数、哈希表、哈希桶

文章目录哈希哈希&#xff08;散列&#xff09;函数常见的哈希函数字符串哈希函数哈希冲突闭散列&#xff08;开放地址法&#xff09;开散列&#xff08;链地址法/拉链法&#xff09;负载因子以及增容对于闭散列对于开散列结构具体实现哈希表&#xff08;闭散列&#xff09;创建…

C++ 泛型编程(一):模板基础:函数模板、类模板、模板推演成函数的机制、模板实例化、模板匹配规则

文章目录泛型编程函数模板函数模板实例化隐式实例化显式实例化函数模板的匹配规则类模板类模板的实例化泛型编程 泛型编程旨在削减重复工作&#xff0c;如&#xff1a; 将一个函数多次重载不如将他写成泛型。 void Swap(int& left, int& right) {int temp left;lef…

你真的了解静态变量、常量的存储位置吗?

文章目录引言C对内存的划分如何落实在Linux上自由存储区和堆之间的问题栈常量区静态存储区静态局部变量静态局部变量、静态全局变量、全局变量的异同macOS系统的测试结果总结引言 在动态内存的博客中&#xff0c;我提到&#xff1a; 在Linux 内存管理的博客中&#xff0c;我提…

C++ 泛型编程(二):非类型模板参数,模板特化,模板的分离编译

文章目录非类型模板参数函数模板的特化类模板的特化全特化偏特化部分参数特化参数修饰特化模板分离编译解决方法非类型模板参数 模板的参数分为两种&#xff1a; 类型参数&#xff1a; 则是我们通常使用的方式&#xff0c;就是在模板的参数列表中在 class 后面加上参数的类型…

数据结构 | B树、B+树、B*树

文章目录搜索结构B树B树的插入B树的遍历B树的性能B树B树的插入B树的遍历B*树B*树的插入总结搜索结构 如果我们有大量的数据需要永久存储&#xff0c;就需要存储到硬盘之中。但是硬盘的访问速度远远小于内存&#xff0c;并且由于数据量过大&#xff0c;无法一次性加载到内存中。…

MySQL 索引 :哈希索引、B+树索引、全文索引

文章目录索引引言常见的索引哈希索引自适应哈希索引B树索引聚集索引非聚集索引使用方法联合索引最左前缀匹配规则覆盖索引全文索引使用方法索引 引言 为什么需要索引&#xff1f; 倘若不使用索引&#xff0c;查找数据时&#xff0c;MySQL必须遍历整个表。而表越大&#xff0c;…

服装店怎么引流和吸引顾客 服装店铺收银系统来配合

实体店的同城引流和经营是实体经济的一个重要的一环&#xff0c;今天我们来分享服装行业的实体店铺怎么引流和吸引、留住顾客&#xff0c;并实现复购。大家点个收藏&#xff0c;不然划走就再也找不到了&#xff0c;另外可以点个关注&#xff0c;下次有新的更好的招&#xff0c;…

MySQL 锁的相关知识 | lock与latch、锁的类型、简谈MVCC、锁算法、死锁、锁升级

文章目录lock与latch锁的类型MVCC一致性非锁定读&#xff08;快照读&#xff09;一致性锁定读&#xff08;当前读&#xff09;锁算法死锁锁升级lock与latch 在了解数据库锁之前&#xff0c;首先就要区分开 lock 和 latch。在数据库中&#xff0c;lock 和 latch 虽然都是锁&…

MySQL 存储引擎 | MyISAM 与 InnoDB

文章目录概念innodb引擎的4大特性索引结构InnoDBMyISAM区别表级锁和行级锁概念 MyISAM 是 MySQL 的默认数据库引擎&#xff08;5.5版之前&#xff09;&#xff0c;但因为不支持事务处理而被 InnoDB 替代。 然而事物都是有两面性的&#xff0c;InnoDB 支持事务处理也会带来一些…

MySQL 事务 | ACID、四种隔离级别、并发带来的隔离问题、事务的使用与实现

文章目录事务ACID并发带来的隔离问题幻读&#xff08;虚读&#xff09;不可重复读脏读丢失更新隔离级别Read Uncommitted (读未提交)Read Committed (读已提交)Repeatable Read (可重复读)Serializable (可串行化)事务的使用事务的实现Redoundo事务 事务指逻辑上的一组操作。 …

MySQL 备份与主从复制

文章目录备份主从复制主从复制的作用备份 根据备份方法的不同&#xff0c;备份可划分为以下几种类型&#xff1a; 热备(Hot Backup) &#xff1a; 热备指的是在数据库运行的时候直接备份&#xff0c;并且对正在运行的数据库毫无影响&#xff0c;这种方法在 MySQL 官方手册中又…