linux c 编程 ------ 进程间通信与同步

在linux下的多个进程间的通信机制叫做IPC(Inter-Process Communication)。

 

1. 管道 (PIPE)

 无名管道只能应用在有关系的两个进程之间,例如fork的父子进程之间,它通过共享fork之前的文件描述符来实现进程之间的通信,管道属于半双工通信

 

 

2. 命名管道(FIFO)

 有名管道也是一种半双工的通信方式,但是它允许无亲缘关系进程间的通信

3. 信号 (signal)

 

4. 消息队列(Message queues)

消息队列是消息的链表,存放在内核中并由消息队列标识符标识.消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等特点.消息队列是UNIX下不同进程之间可实现共享资源的一种机制,UNIX允许不同进程将格式化的数据流以消息队列形式发送给任意进程.对消息队列具有操作权限的进程都可以使用msget完成对消息队列的操作控制.通过使用消息类型,进程可以按任何顺序读信息,或为消息安排优先级顺序.

 

5. 信号量(Semaphore)

 

6. 共享内存(Share Memory)

 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问.共享内存是最快的IPC(进程间通信)方式,它是针对其它进程间通信方式运行效率低而专门设计的.它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步与通信.

7. 内存映射(Memory Map)

 

8. 套接字

 

PIPE和FIFO用来实现进程间相互发送非常短小的、频率很高的消息;这两种方式通常适用于两个进 程间的通信。

共享内存用来实现进程间共享的、非常庞大的、读写操作频率很高的数据(配合信号量使用);这 种方式通常适用于多进程间通信。

其他考虑用socket。这里的“其他情况”,其实是今天主要会碰到的情况:分布式开发。在多进 程、多线程、多模块所构成的今天最常见的分布式系统开发中,socket是第一选择。 消息队列,现在建议不要使用了 ---- 因为找不到使用它们的理由。消息队列说白了就是“高级一点 儿的PIPE/FIFO”,但是这种“高级”相较于现在常见的业务场景来说其实一点儿都不高级:没有 容灾、没有弹性伸缩......因此不建议使用消息队列。现在有很成熟的各种MQ,比如RabbitMQ、 ZeroMQ等。

一句话,业务场景很简单、对性能有要求,就用PIPE、FIFO、共享内存,业务场景复杂,就用现在已经很成熟的那些MQ。 在实际中,我个人感觉,PIPE和FIFO可以偶尔使用下,共享内存都用的不多了。在效率上说, socket有包装数据和解包数据的过程,所以理论上来说socket是没有PIPE/FIFO快,不过现在计算 机上真心不计较这么一点点速度损失的。你费劲纠结半天,不如我把socket设计好了,多插一块 CPU来得更划算。

另外,进程间通信的数据一般来说我们都会存入数据库的,这样万一某个进程突然死掉或者整个服 务器死了,也不至于丢失重要数据、便于回滚到之前的状态。从这个角度考虑,适用共享内存的情 况也更少了,所以socket使用得更多。 再多说一点关于共享内存的:共享内存的效率确实高,但它的重点在“共享”二字上。如果的确有 好些进程共享一大块数据(如果把每个进程都看做是类的对象的话,那么共享数据就是这个类的 static数据成员),那么共享内存就是一个不二的选择了。但是在面向对象的今天,我们更多的时候 是多线程+锁+线程间共享数据。因此共享进程在今天使用的也越来越少了。

不过,在面对一些极度追求效率的需求时,共享内存就会成为唯一的选择,比如高频交易系统。除此以外,一般是不需要特意使用共享内存的。

另外,PIPE和共享内存是不能跨LAN的(FIFO可以但FIFO只能用于两个进程通信)。如果你的分布式系统随着需求的增加而越来越大所以你想把不同的模块放在不同机器上而你之前开发的时候用 了PIPE或者共享内存,那么你将不得不对代码进行大幅修改......同时,即使FIFO可以跨越LAN,其代码的可读性、易操作性和可移植性、适应性也远没有socket大。这也就是为什么一开始说socket 是第一选择的原因。

最后还有个信号简单说一下。 请注意,是信号,不是信号量。信号量是用于同步线程间的对象的使用的。 信号也是进程间通信的一种方式。比如在Linux系统下,一个进程正在执行时,你用键盘按Ctrl+c, 就是给这个进程发送了一个信号。进程在捕捉到这个信号后会做相应的动作。 虽然信号是可以自定义的,但这并不能改变信号的局限性:不能跨LAN、信息量极其有限。 在现代的分布式系统中,通常都是消息驱动:即进程受到某个消息后,通过对消息的内容的分析然后做相 应的动作。如果你把你的分布式系统设置成信号驱动的,这就表示你收到一个信号就要做一个动作而一个 信号的本质其实就是一个数字而已。这样系统稍微大一点的话,系统将变得异常难以维护;甚至在很多时候,信号驱动是无法满足我们的需求的。 因此现在我们一般也不用信号了。

因此,请记住:除非你有非常有说服力的理由,否则请用socket。

顺便给你推荐个基于socket的轻量级的消息库:ZeroMQ。

 

posted @ 2020-11-25 17:27  流水灯  阅读(8)  评论(0编辑  收藏  举报