进程中的五种通信方式介绍

进程间通信(InterProcess Communication)是指在不同的进程之间传播或者交换信息。
IPC的方式通常有管道(无名和有名)、消息队列、共享存储、信号量、Socket以及Streams等。
其中Socket和Streams支持不同主机之间的两个进程IPC。

管道

(一般指的是无名管道)是UNIX系统IPC最古老的方式。
特点:

  1. 半双工(数据只能在一个方向上流动),固定的读端和写端;
  2. 只能在有亲缘关系的进程之间进行通信(兄弟或者父子进程);
  3. 可以看成是一个特殊的文件, 对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
    利用LInux的C编程,管道是这样表示的:
#include <unistd.h>
int pipe(int fd[2]);    // 返回值:若成功返回0,失败返回-1

在这里插入图片描述在这里插入图片描述
若要数据流从父进程流向子进程,则关闭父进程的读端(fd[0])与子进程的写端(fd[1]);反之,则可以使数据流从子进程流向父进程。

提一种新的PIPE:
高级管道(popen):将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。

FIFO命名管道

命名管道是一种文件类型,具有以下几个特点:

  1. 也是半双工,但是可以在无关的进程之间进行数据交换;
  2. FIFO有路径名与之关联,以一种特殊的设备文件的形式存在于文件系统
    在这里插入图片描述
    详见:https://www.cnblogs.com/zgq0/p/8780893.html

消息队列

消息队列是消息的链表,存放在内核中。一个消息队列有一个队列标识符(队列ID)来标识。
消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
在这里插入图片描述
其特点有:

  1. 消息队列是面向记录的,其中的消息具有特定的格式和特定的优先级
  2. 消息队列独立于发送和接收进程。 进程终止时,消息队列及其内容并不会被删除。
  3. 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。

信号量

信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量常作为一种锁机制,用于实现进程间的互斥与同步(或者同一个进程间的不同进程间的同步),而不是用于存储进程间通信数据。
具有以下几个特点:

  1. 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存
  2. 信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
  3. 每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数
  4. 支持信号量组

最简单的信号量是只能取 0 和 1 的变量,这也是信号量最常见的一种形式,叫做二值信号量(Binary Semaphore)。而可以取多个正整数的信号量被称为通用信号量

Linux 下的信号量函数都是在通用的信号量数组上进行操作,而不是在一个单一的二值信号量上进行操作。

共享内存

共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。j具有以下特点:

  1. 共享内存是最快的一种 IPC,因为进程是直接对内存进行存取
  2. 因为多个进程可以同时操作,所以需要进行同步
  3. 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。

为甚共享内存是最快的IPC:因为共享内存对消息的复制只有两次(数据来源->共享内存->数据目的地)。
其他PiPE以及消息队列等方式都因为有缓冲区的存在,读写都要经过缓冲区,所以是四次复制。
在这里插入图片描述
上图中进程的数据存储区域详见我的另一篇文章:《进程内存空间五种 数据区》

共享内存在Linux中用c语言表示方法如下:

#include <sys/shm.h>
// 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
int shmget(key_t key, size_t size, int flag);
// 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
void *shmat(int shm_id, const void *addr, int flag);
// 断开与共享内存的连接:成功返回0,失败返回-1
int shmdt(void *addr); 
// 控制共享内存的相关信息:成功返回0,失败返回-1
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);

当用shmget函数创建一段共享内存时,必须指定其 size;而如果引用一个已存在的共享内存,则将 size 指定为0 。

当一段共享内存被创建以后,它并不能被任何进程访问。**必须使用shmat函数连接该共享内存到当前进程的地址空间,**连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问。

shmdt函数是用来断开shmat建立的连接的。注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。

shmctl函数可以对共享内存执行多种操作,根据参数 cmd 执行相应的操作。常用的是IPC_RMID(从系统中删除该共享内存)。

上述五种IPC方式总结:

1.管道:速度慢,容量有限,只有父子进程能通讯

2.FIFO:任何进程间都能通讯,但速度慢

3.消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题

4.信号量:不能传递复杂消息,只能用来同步

5.共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题。相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存

转自:https://www.cnblogs.com/zgq0/p/8780893.html

信号 ( sinal )

信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生

套接字(Socket)

套解字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。(即网络之间的进程通信)
在这里插入图片描述

streams

流管道,可以双向传输

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值