文章目录

  • 进程间通信
    • 一、进程间通信的概念
    • 二、进程间通信的方式
      • 1、管道
        • I.匿名管道
          • a.匿名管道的创建
          • b.匿名管道的使用事项
        • II.命名管道
          • a.命名管道的创建
          • b.命名管道的使用事项
        • III.管道的特点
        • IV.管道文件的意义
      • 2、共享内存
        • I.共享内存的创建
          • 创建共享内存示例
        • II.共享内存的使用(attach)
          • 使用共享内存示例
        • III.共享内存的分离(de-attach)
        • IV.共享内存的控制(销毁)
        • V.指令查看和销毁共享内存
        • VI.共享内存的特性
      • 3、信号量
        • I.信号量实现同步机制
        • II.信号量实现互斥机制
      • 4、消息队列
        • 消息队列的特性
      • 5、信号
      • 6、套接字

进程间通信

一、进程间通信的概念

所谓进程间通信,就是让不同进程在内核的帮助下看到同一份系统资源,以达到数据交互的目的。

二、进程间通信的方式

Linux提供了六种进程间通信的机制:管道共享内存、信号量、消息队列、信号、套接字。

1、管道

管道基于管道文件,本质上是一个存在于内核缓冲区的环形队列,满足先进先出(FIFO)原则,允许两个进程以**“生产者/消费者模型”**进行通信。

管道分为匿名管道和命名管道,他们拥有几乎相同的底层原理,区别就是创建和使用方式不同

I.匿名管道

匿名管道只能由**“有血缘关系”**的进程使用,即拥有共同祖先的进程,常见的就是父子进程。

a.匿名管道的创建

进程通过系统调用pipe()完成匿名管道的创建:

int pipe(int pipefd[2])

成功则返回0,失败则返回-1。

其中pipefd是一个输出型参数,表示匿名管道文件的两个文件描述符:

  • pipefd[0]具有==“只读”==属性,进程可通过该文件描述符进行读操作
  • pipefd[1]具有==“只写”==属性,进程可通过该文件描述符进行写操作

b.匿名管道的使用事项

匿名管道使用文件描述符继承的方式保证进程通信:

在父进程使用pipe创建匿名管道时,文件描述符表中就会维护两个文件描述符pipefd[0]和pipefd[1],子进程会继承父进程的文件描述符表。

但是,匿名管道是一种单向通信方式,只能有一个进程读,另一个进程写。因此,负责读的进程最好将写文件描述符关闭,负责写的进程最好将读文件描述符关闭,避免用户的误操作!

II.命名管道

不同于匿名管道仅使用文件描述符进行操作,命名管道是一个具有文件名的真正的文件,拥有独立的inode,因此允许任意进程打开该文件以实现进程间通信。

注:与匿名管道相同,命名管道文件只在使用时将数据存在内核缓冲区中。

a.命名管道的创建
  1. 使用mkfifo命令创建命名管道:

mkfifo pipe_file_name

  1. 使用mkfifo函数创建命名管道:

int mkfifo(const char *pathname, mode_t mode)

其中pathname是管道文件的存储路径(包括文件名);mode是该文件的权限(八进制);成功则函数返回0,失败返回-1。


b.命名管道的使用事项

在确定好哪个进程读,哪个进程写后,就可以通过对应的方式(O_RDONLY/O_WRONLY)打开管道文件,利用read/write进行读写,完成进程间通信。

III.管道的特点

  1. 管道采取半双工的通信模式,一个进程只能选择写或者读;
  2. 当管道的读端进程全部退出时,写端进程会收到SIGPIPE信号而退出;
  3. 当管道的写端进程全部退出时,读端进程会最终读到EOF(即read返回值为0);
  4. 管道基于**“生产者消费者模型”**,自带同步机制,因此是并发安全的;
  5. 管道是基于字节流的,进程以字符串格式对管道文件读写;
  6. 管道文件有大小限制,经测试,最大容量为64KB
  7. 如果写端一次写入的数据小于PIPE_BUF(4KB),那么内核将保证写操作的原子性;否则,写操作的原子性将不被保证。这也是为什么ulimit -a命令查看得到的pipe size为4KB而测试的最大容量为64KB的原因。

IV.管道文件的意义

  • 管道文件能够保证实时通信,而普通文件存在于磁盘,内核并不会立即将缓冲区内容刷新到磁盘,因此无法完成实时通信。

  • 管道文件的读写是并发安全的,相当于内核为用户提供了一种同步通信机制,使用起来比较方便

2、共享内存

共享内存是一段由内核维护的物理内存空间。

由于不同进程拥有独立的虚拟地址空间和页表,因此可以将共享内存通过进程页表映射到不同进程地址空间的共享区。如此,不同进程就可以通过自己的虚拟地址访问相同的物理地址,从而达到通信的目的。

I.共享内存的创建

int shmget(key_t key, size_t size, int shmflg)

  • key:用来标识共享内存的键值,不同进程可以通过相同的key获取到同一块共享内存。key可以由用户随意指定,也可以通过ftok函数获取。
  • size:向系统申请的共享内存大小。建议申请PAGE_SIZE(虚拟页大小)的整数倍,因为系统是以页大小的整数倍开辟共享内存的,如果size不是页的整数倍,那么系统为了对齐而额外开辟的空间会导致内存浪费
  • shmflg:标志位。如果以key为标识的共享内存不存在,则可以通过IPC_CREAT创建该内存;如果以key为标识的共享内存已存在,且使用IPC_CREAT | IPC_EXCL时,则shmget函数返回-1;该标志位还可以用来设置共享内存的读写权限(按位或八进制权限)。
  • RetVal:成功则返回一个shmid,之后通过该id使用共享内存;失败则返回-1。

注:尽管申请的空间会被对齐至PAGE_SIZE的整数倍,但是用户能够使用的大小依然是size


key_t ftok(const char *pathname, int proj_id)

pathname是一个路径名,proj_id是一个项目id,它们都可以随意填写。对于相同的pathnameproj_idftok()会返回相同的key值。

创建共享内存示例
key_t key = ftok(PATH, PROJ_ID);
int shmid = shmget(key, 4096, IPC_CREAT | IPC_EXCL | 0644);

II.共享内存的使用(attach)

void *shmat(int shmid, const void *shmaddr, int shmflg)

  • shmidshmget函数成功执行返回的id值;
  • shmaddr:可以由用户指定一个共享区的地址作为共享内存映射到本进程地址空间的起始地址,一般设为NULL,表示由系统选取合适的地址;
  • shmflg:指明对共享内存的权限,如SHM_RDONLY表示只读,不过该参数一般设为0,表示使用该内存的创建进程设置的权限
  • RetVal:返回将shmid标识的共享内存映射到共享区的起始地址,用户可以通过该地址读写共享内存,进行通信。

注:该函数用来实现对共享内存的attach(挂接)。只有挂载到同一个共享内存的进程才能通过这段内存通信。

使用共享内存示例
// 写进程wrproc.c每秒追加一个字符x
void* addr = shmat(id, NULL, 0);
for (int i = 0; i < shm_size; ++i)
{addr[i] = 'x';sleep(1);
}// 读进程rdproc.c每秒打印一次共享内存的内容
void* addr = shmat(id, NULL, 0);
while (int i = 0; i < shm_size; ++i)
{sleep(1);printf("%s\n", addr);
}

III.共享内存的分离(de-attach)

int shmdt(const void *shmaddr)

shmaddrshmat函数成功执行返回的起始地址,进程调用该函数表示不再使用这段共享内存,即de-attach(分离,取消挂接)。

如果成功分离则返回0,失败返回-1。

IV.共享内存的控制(销毁)

int shmctl(int shmid, int cmd, struct shmid_ds *buf)

  • shmidshmget函数成功执行返回的id值;
  • cmd:控制选项。IPC_RMID,表示销毁这段共享内存;另外还有IPC_STATIPC_SET等选项,这里不关注;
  • buf:指向一个保存着共享内存的模式状态和访问权限的数据结构,当使用IPC_RMID销毁共享内存时,该参数设为NULL即可。

V.指令查看和销毁共享内存

使用ipcs可以查看进程间通信的相关信息,其中ipcs -m仅查看共享内存的相关信息。

ipcrm -m id即可删除指定id的共享内存。

VI.共享内存的特性

  1. 不同的进程可以通过共享内存的起始虚拟地址直接访问相同的一块物理内存,避免了管道文件需要将数据从用户拷贝到内核的问题,因此该通信方式效率很高。
  2. 虽然效率较高,但是共享内存没有同步功能,因此需要用户自己通过**“信号量”**等手段实现并发安全。
  3. 共享内存的生命周期是随内核的。因此一旦不再使用,一定要使用shmctl函数或 ipcrm -m指令销毁它。

3、信号量

信号量(semaphore)是为了弥补"多进程竞争共享内存导致数据错乱"而引入的同步和互斥机制。

信号量本质就是一个计数器,对信号量的操作主要是PV操作

  • P 操作:把信号量减1。

    1. 相减后如果信号量 < 0,则表明资源已被占用,进程需阻塞等待,且当前阻塞等待的进程数为信号量的绝对值
    2. 相减后如果信号量 >= 0,则表明还有资源可用,进程可正常继续执行。
  • V 操作:把信号量加1。
    1. 相加后如果信号量 <= 0,则表明当前有阻塞中的进程,将该进程唤醒运行。
    2. 相加后如果信号量 > 0,则表明当前没有阻塞中的进程。

PV操作具有原子性,因此又被称为PV原语

I.信号量实现同步机制

进程同步,即让并发的进程按要求有序地执行。

以两个进程之间的同步为例:

  1. 设置同步信号量S,初始为0。
  2. B进程进行P(S)操作,阻塞等待信号量
  3. A进程进行V(S)操作,此时B进程可以获得信号量,继续向下执行

如此,就保证了A进程在B进程之前运行。

II.信号量实现互斥机制

进程互斥,即保证不同进程不能同时进入一个临界区。

实现步骤:

  1. 设置互斥信号量S,初始为1。
  2. 进程在进入临界区之前执行P(S)以获得互斥信号量,此时其它进程必须阻塞等待。
  3. 进程在退出临界区之后执行V(S)以释放互斥信号量,此时其它进程可以获取信号量。

4、消息队列

消息队列,即MQ(Message Queue),本质是保存在内核中的消息链表

消息队列的特性

  1. 待发送的数据会被分成一个一个独立的数据单元,也就是消息体(数据块)。由于消息体是发送方和接收方约定好的数据类型,因此每个消息体都是固定大小的,而非像管道那样的字节流。
  2. 消息体的生命周期随内核,只有被读取或操作系统关闭时,它们才会被释放。
  3. 消息队列基于==“生产者消费者模型”==,是并发安全的。
  4. 和管道通信一样,消息队列的数据同样需要进行用户和内核之间的相互拷贝,因此相比于共享内存效率差一些。

5、信号

信号是进程间通信机制中唯一的一个异步通信机制。

当A进程向B进程发送信号时,B进程不一定立即处理该信号,而是在CPU切换到用户态之前检查是否有信号,然后进行对应处理。
信号详解戳这里

6、套接字

套接字可用于相同主机上的两个进程或是网络上不同主机上的两个进程进行通信,详见网络编程socket部分。
套接字详解戳这里

进程间通信的六大方式相关推荐

  1. 旅游捞金的六大方式,玩着把钱赚了

    生活在繁忙的大都市中,面对劳累的工作和繁琐的家事,一场说走就走的旅行无疑是肆放焦虑的良药. 但现实是"说走就走"绝不是那样简单的. 时间要调配.工作需处理.路线应规划...... ...

  2. Android进程间通信 - 几种方式的对比总结

    文章目录 什么是RPC 什么是IPC 参考 什么是RPC RPC(Remote Procedure Call)即远程过程调用,它是一种通过网络从远程计算机程序上请求服务,在不需要了解底层网络技术的协议 ...

  3. 进程间通信——几种方式的比较和详细实例

    由网上资源整合: 1.进程间通信的定义 2.几种通信方式的比较 3.几种通信方式的详细实例 1.进程间通信的定义 进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的 ...

  4. 进程间通信的方式总结

    进程间通信就是在不同进程之间传播或交换信息. 进程间通信的目的如下: ①数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间. ②共享数据:多个进程想要操作共享数据, ...

  5. linux系统线程通信的几种方式,Linux进程间通信-线程间通信

    Linux作为一种新兴的操作系统,几乎支持所有的Unix下常用的进程间通信方法:管道.消息队列.共享内存.信号量.套接口. 1.管道 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动 ...

  6. 进程间通信方式——管道

    进程间通信 1.进程间通信概念及方式 2.管道 2.1 管道概念 2.2 管道的原理 2.3 管道的局限性 2.4 管道的优缺点 3.管道创建与应用 3.1 pipe函数创建并打开 3.2 程序实现 ...

  7. 进程间通信(IPC)的几种方式

    进程间通信(IPC) 1.常见的通信方式 2.低级IPC方法 文件 3.常用于本机的IPC机制 3.1无名管道pipe 3.2命名管道FIFO 3.3消息队列MessageQueue 3.4共享内存S ...

  8. 进程间通信的六种常见方式

    目录 进程间通信(IPC): 一.管道 二.FIFO 三.消息队列 四.共享内存 五.信号 六.信号量 七.进程间通信方式总结: 进程间通信(IPC): 进程间通信的方式有很多,这里主要讲到进程间通信 ...

  9. linux进程间通信方式及比较

    进程间的通信方式: 1.管道(pipe)及有名管道(named pipe): 管道可用于具有亲缘关系进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信. 2.信号(sig ...

最新文章

  1. 8月6日云栖精选夜读 | 阿里云CPFS在人工智能/深度学习领域的实践
  2. Linux系统资源管理 之 硬件信息
  3. 全方位讲解硬件防火墙的选择
  4. 7.多媒体☞图像图形拍照
  5. 让CMD窗口显示中文[JAVAC输出中文错误信息乱码的解决]
  6. Bootstrap源码解读之栅格化篇
  7. php无限极,PHP无限极分类
  8. mysql 数据类型大全_MySQL 数据类型_mysql数据类型大全
  9. 区块链 以太坊 solidity 如何比较2个字符串相等
  10. C++ 入门5 ---- 类和动态内存分配(一)
  11. 一个失败软件项目的思考
  12. Qt如何调用xlsl的方法!
  13. Excel使用VBA自动调整列宽
  14. 会做饭的机器人曰记_会做饭的机器人!
  15. 学习《华为基本法》(5):经营重心
  16. windows和linux系统文件目录
  17. 腾讯云服务器域名公安备案记录
  18. 隐枚举法matlab程序,隐枚举法例题
  19. jsnes-FC模拟器-在线玩fc游戏
  20. NPL基础入门之新闻本分类赛题理解Test1

热门文章

  1. 如何临时修改ip地址,永久修改ip地址
  2. 如何给App快速搭建虚拟服务器
  3. android 麦克风 动画,录音麦克风动画效果
  4. altium designer原理图生成pcb
  5. 关于电子科技大学学生阅读情况调查报告
  6. 霖呆呆的近期面试128题汇总(含超详细答案)
  7. c++ bitset类用法
  8. h3cr4900g3安装系统_H3C服务器安装Windows操作系统
  9. SSD Performance测试简介
  10. 线性代数 | 知识点总结(上)