linux下的进程间通信(IPC)


一、进程间通信(IPC)是什么?

操作系统为用户提供的几种用于进程间进行通信的方式。
(管道,共享内存,消息队列,信号量)

目的:进程具有独立性。
(每个进程都有自己的虚拟地址空间,访问的都是自己的虚拟地址,将一个数据的地址就算交给其他进程,其他进程在自己的虚拟地址空间映射中实际上是没有这个数据的);
因此进程间无法直接通信,但是在以后的中大型项目中多个进程协同工作很常见,则进程间通信就尤为重要。

进程间通信根据不同的应用场景,使用不同方式。

二、四种通信方式

1.管道-PIPE

生活中的管道:自来水管,天然气管道,目的都是传输资源;
且在传输资源中具有半双工通信的特性。

半双工通信: 可以选择方向的单向通信。(数据出发端由用户决定)。
作用: 用于实现进程间的数据传输
本质: 内核中的一块缓冲区(内存),多个进程访问同一个缓 冲区实现通信。

(1)管道分类

外在用法不同,但是本质相同
①匿名管道:内核中开辟的这块缓冲区,没有标识符,无法被其他进程找到(只能用于具有亲缘关系的进程间通信)
②命名管道:内核中开辟的这块缓冲区,有标识符,能被其他进程找到(可用于同一主机上任意进程间通信)
在这里插入图片描述

一个进程通过系统调用在内核中创建了一个匿名管道,为了能让用户操控这个管道,因此返回了文件描述符作为这个管道的操作句柄。
其他进程因为没有这个管道标识符,所以无法通信;

但是,如果这个创建管道的进程创建了一个子进程,这时候子进程复制了父进程(文件描述信息表),所以子进程相当于也有文件描述符可以操作该管道
—匿名管道只能用于具有亲缘关系的进程间通信。
只有通过子进程复制父进程才能获取到同一个管道的操作句柄。
在这里插入图片描述

命名管道: 一个进程创建一个命名管道,这个命名管道会在文件系统中创建出一个管道文件(可以看得到的,实际上就是管道的名字),多个进程通过打开同一个管道文件,访问内核中同一个缓冲区实现通信。

注意:命名管道文件只是一个文件,是为了让进程找到同一个缓冲区。

(2)接口

匿名管道的创建:

int pipe(int pipefd[2]);
pipefd[2]:具有2个int元素的数组,用于接收管道创建成功所返回的文件描述符-操作句柄
pipefd[0]:用于从管道中读取数据;
pipefd[1]:用于从管道写入数据
返回值:成功返回0;失败返回-1;

注意:匿名管道的创建一定要在创建子进程之前,才能被子进程复制到操作句柄

管道的读写特性:
如果管道中无数据,则read会阻塞;
如果管道中数据满了,则write会阻塞.
阻塞:为了完成一个功能,发起调用,功能无法完成则调用一直等待;
非阻塞:为了完成一个功能,发起调用,功能无法完成则调用报错返回;
其他特性:
管道的操作是会阻塞的,但是如果管道所有写端被关闭
(管道已经不可能写入数据),这时候read读取完管道中的数据后,就不再阻塞了,而返回0(表示没人写入了,而不是没数据了)。

管道的所有读端被关闭(管道没人读取数据),
则继续write就会触发异常,进程退出。

(3)特性总结

①半双工通信
②没有数据read阻塞;数据满了write阻塞
③所有读端关闭,则write触发异常,进程退出
④所有写段关闭,则read读完数据后不再阻塞,返回0

shell中的管道符的实现: ps -ef|grep***
管道符:连接两个命令,将前面命令的输出结果,作为后面命令的输入传递给后面命令进行处理。
ps-ef: ps进程,功能是将所有的进程信息打印出来(写入到标准输出)
grep ssh: grep进程,不断捕捉标准输入数据进行字符串匹配后输出;

(4)管道符的实现

让前面的命令进程,不再写入数据到标准输出,而是写入管道中
让后面的命令进程,不再从标准输入读取数据,而是从管道读取

  1. 创建一个管道
  2. 创建ps进程(创建一个子进程,程序替换为ps),
    在程序替换前,将标准输出重定向到管道
  3. 创建grep进程(创建一个子进程,子进程替换为grep),
    在程序替换前,将标准输入重定向到管道
  4. 等待命令子进程退出。

匿名管道:
(1)本质:内核中的一块缓冲区(没有标识符)
(2)操作:int pipe(int pipefd[2])
(3)特性:
半双工通信;
①数据先进先出(流式传输);
②管道没有数据read阻塞,数据满了write阻塞;
③所有读端关闭write触发异常,所有写端关闭则read返回0;
④只能用于具有亲缘关系的进程间通信。

命名管道:
可以用于同一主机上的任意进程间通信
(1)本质:
内核中的一块缓冲区(但是具有一个可见于文件系统的管道文件作为名字,多个进程通过打开同一个管道文件访问同一个管道)
(2)原理:
管道的缓冲区在没有进程确定要写数据且有进程读取数据的情况下,缓冲区就没必要开辟,空占资源
(3)操作:
命令:mkfifo filename 创建命名管道文件
接口:int mkfifo(char *filename,mode_t mode);
创建命名管道文件,并不会立即创建内核中的缓冲区,而是在有进程访问的时候才会开辟(写时拷贝的思想,提高效率)
(4)独特的打开特性:
命名管道文件以只读打开,则阻塞,直到管道文件被其他进程以写的方式打开;
命名管道文件以只写打开,则阻塞,直到管道文件被其他进程以写的方式打开;

(5)管道总结

本质:内核中的缓冲区
分类:匿名管道/命名管道
匿名管道:仅能用于具有亲缘关系的进程间通信
命名管道:可以用于同一主机上任意进程间通信
操作:

int pipe(int pipefdp[2]);
 int mkfifo(char *filename, mode_t mode);

特性:
①半双工通信
②生命周期随进程(在不人为干预的情况,所有打开管道的进程退出,则管道缓冲区被释放)
③管道提供流式传输(以字节为单位的数据先进先出,所有读端关闭write异常,所有写端关闭read返回0不再阻塞)
④管道自带同步与互斥
同步:

操作按照一定秩序进行,
写入数据才能读取数据,
(没有数据则read阻塞;数据满了write阻塞,读取了才能继续写)

互斥:

操作都是安全可靠的。

(如果没有互斥,则两个进程若同时向管道写入数据
则有可能出现交叉写入,数据混乱)

读写大小不超过PIPE_BUF(4096字节)大小则保证原子操作;
原子操作:要么一次完成,要么不做的操作,中间不会被打断。

2. 共享内存

(1)特性

①所有进程间通信方式中最快的一种;
共享内存周期随内核,在不人为删除的情况, 所有映射进程退出也不会释放共享内存。

(2)速度快

因为通过虚拟地址直接访问内存,相较于其他方式少了两次用户空间与内核空间之间的数据拷贝。

(3)本质原理

开辟一块物理内存,需要进行通信的进程将这块物理内存映射到自己的虚拟地址空间中,直接使用自己的用户空间地址访问。

共享内存是一种覆盖式操作.

(4)操作流程

  1. 创建或打开共享内存
  2. 将共享内存映射到虚拟地址空间
  3. 内存操作(memcpy,printf)
  4. 解除映射关系
  5. 删除共享内存(共享内存不会被立即删除,而是等到共享内存的映射连接数为0时才会删除)

(1)创建或打开

int shmget(key_t key, size_t size, int shmflag);
   key:共享内存标识符(为了让多个进程找到同一个)
   size:需要创建的共享内存大小(仅创建时有效)
   shmflag: IPC_CREAT  |  IPC_EXCL	
      IPC_CREAT:不存在则创建,存在则打开。
         IPC_EXCL与IPC_CREAT搭配使用,
         表示存在则报错,不存在则创建打开。
   mode:  0664 设置共享内存访问权限
返回值:成功返回一个非负整数-操作句柄;失败返回-1。

(2)建立映射关系

void *shmat(int shm_id, void *shmaddr,int shmflag)
     shm_id: shmget返回的操作句柄 
     shmaddr: 通常置NULL,让系统自动分配建立映射
     shmflag: SHM_RDONLY-只读; 0-默认是可读可写
返回值:成功返回映射的首地址;失败返回(void*)-1。

(3)解除映射关系

int shmdt(void *shm_start)
    shm_start:映射首地址-shmat的返回值
返回值:成功返回0;失败返回-1。

(4)删除共享内存

int shmctl(int shm_id, int cmd, struct shmid_ds *buf)
     shmid:操作句柄
     cmd:IPC_RMID -标记删除(不再接受新的映射)
     buf:用于获取共享内存信息,用不上就置NULL
   返回值:成功返回0; 针对IPC_RMID失败返回-1。

(5)共享内存总结

本质原理: 开辟一块内存空间,多个进程将同一块空间映射到自己的虚拟地址空间进行访问,实现数据共享。

特性:
①最快的进程间通信方式
②生命周期随内核

注意:
①共享内存是一种覆盖式内存操作
②共享内存的操作需要考虑安全问题(没有互斥同步关系)

3.消息队列

(1)本质

内核中创建的一个优先级队列;
具有标识符能被其他进程找到,
多个进程通过访问同一个队列,通过添加或者获取节点实现通信。

消息队列传输的都是数据节点
节点中包含两个信息:
1.类型 2.数据

类型作用:用于身份区分; 优先级

(2)特性

  1. 半双工通信
  2. 自带同步互斥
  3. 生命周期随内核

本次所讲的进程间通信都是systemV标准的,
POSIX标准也有自己的进程间通信方式

4.信号量

(1)本质

内核中的一个计数器

(2)作用

实现进程间的同步与互斥(保护进程间对临界资源的操作)

临界资源:大家都能访问的资源.

(3)如何实现保护操作

同步: 通过一些条件使进程资源的访问更加有序。
互斥: 通过让进程同一时间对资源的唯一访问保证操作安全。

Eg:停车场的计数牌-统计空闲车位,为0则不能停车。

(4)信号量实现同步与互斥原理

通过计数器对资源进行计数:
若计数大于0则表示可以访问资源;
若资源小于0则表示不能访问,则阻塞进程;

其他进程生产一个资源后,计数+1,唤醒一个阻塞进程
操作:

P操作: 在进程访问资源之前进行,判断计数是否大于0
大于0,则正确返回,计数-1;
小于0,则阻塞进程,计数-1;

V操作: 当产生一个新的资源后,计数+1,唤醒一个阻塞进程

(1)实现互斥:

初始化临界资源计数器为1;(表示资源只有1个)
在访问临界资源之前进行P操作;
在访问临界资源之后进行V操作。

(2)实现同步:

根据资源数量初始化计数器,
访问/获取资源之前进行P操作;
产生一个新资源之后进行V操作。

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值