共享内存,管道,socket等进程间通信方式的优缺点

来源:互联网 发布:南山软件产业基地一栋 编辑:程序博客网 时间:2024/04/28 23:34

进程间通信的方式有很多,常见的有信号,信号量,消息队列,管道,共享内存,和socket等,这里我们主要讨论管道,共享内存,和socket,其他的比较简单只做简单的介绍。

信号:信号主要用于通知某个进程发生了什么事,就像你打电话通知某个人某件事一样,事先注册号信号相应的注册函数就可以了。

信号量:信号量实际上是一个计数器,通常在多线程或者多进程开发中会用到,主要用来控制多线程多进程对于共享资源访问,通常配合锁来实现同时只有一个进程或者线程操作共享资源,防止数据的不同步。

消息队列:消息队列是消息的链表,存放在内核中并由消息队列表示符,我们可以在两个进程之间通过消息队列来实现进程间通信。不过消息队列在工作中好像并不怎么常用。

接下来主要谈谈剩下的三种,这些是我们经常会用到的。

管道分为有名管道和无名管道两种

无名管道 :主要用于父进程与子进程之间,或者两个兄弟进程之间。在linux系统中可以通过系统调用建立起一个单向的通信管道,且这种关系只能由父进程来建立。因此,每个管道都是单向的,当需要双向通信时就需要建立起两个管道。管道两端的进程均将该管道看做一个文件,一个进程负责往管道中写内容,而另一个从管道中读取。这种传输遵循“先入先出”(FIFO)的规则。

有名管道:命名管道是为了解决无名管道只能用于近亲进程之间通信的缺陷而设计的。命名管道是建立在实际的磁盘介质或文件系统(而不是只存在于内存中)上有自己名字的文件,任何进程可以在任何时间通过文件名或路径名与该文件建立联系。为了实现命名管道,引入了一种新的文件类型——FIFO文件(遵循先进先出的原则)。实现一个命名管道实际上就是实现一个FIFO文件。命名管道一旦建立,之后它的读、写以及关闭操作都与普通管道完全相同。虽然FIFO文件的inode节点在磁盘上,但是仅是一个节点而已,文件的数据还是存在于内存缓冲页面中,和普通管道相同。

管道有很多致命的缺点,比如只能在具有亲缘关系的进程间通信,只能单向传输数据,另外管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小,管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,最后就是管道操作不当很容易阻塞。因此管道虽然偶尔会见到,但是很少人会用。

共享内存:这个是经常用的,共享内存号称是最快的进程间通信方式,她在系统内存中开辟一块内存区,分别映射到各个进程的虚拟地址空间中,任何一个进程操作了内存区都会反映到其他进程中,各个进程之间的通信并没有像copy数据一样从内核到用户,再从用户到内核的拷贝。这种方式可以像访问自己的私有空间一样访问共享内存区,但是这事这种特性加大了共享内存的编程难度,对于数据的同步问题是一个难点,没有一定的经验很 容易造成数据的混乱。但是我们可以使用一个折中的方法,我们可以结合它和管道来使用。

举个例子进程A和B通信,如果我们用一块共享内存区来实现它们的通信,对于数据的同步是个令人头疼的问题,但是我们可以用两个共享内存区。大笑

内存区 1 ,A->B,A只能写数据,B只能读数据

内存区 2, B->A,A只能读数据,B只能写数据

这样就不会因为,多个进程同时鞋一块内存造成数据的混乱了,看起来是不是有点像管道,其实就是管道的机制,但是不同的是,她的速度要比管道快的多,他的数据大小没有限制(当然不能超过系统的内存大小),当然也不会有阻塞问题。但是这种方式也有明显的缺点,它只适合点对点的通信,如果要多个进程间通信,内存区的数量会呈线性增长,会造成数据的冗余,并且管理起来也会变得困难,如果你的进程数量在各位数着中方式是一个好的选择,否则就要采用一块共享内存,同时做好数据的同步了。

最后一点,通过名字就知道它是基于内存的,所以他只能在同一主机上使用,如果我们要做分布式应用或者跨物理机通信,那么socket就是我们唯一的选择了。

socket是一种面相网络的一种进程间通信方式,只要有网络存在,它可以跨越任何限制。socket编程是一个宽泛的说法,对于我们程序猿来说tcp,udp,http是我们经常用的一些网络协议。当然socket也是我们用的最多的,他的限制住要在与带宽,网络延时和连接数量的限制等。这也是我们在开发服务程序时都要面对c10k问题的原因。

下面看一段别人对于使用这些方式的前提的看法:(来源:http://blog.csdn.net/fengye245/article/details/7783717)

1. 联网的还是非联网的.IPC适用于单台主机上的进程或线程间的.如果应用程序有可能分布到多台主机上,那就要考虑使用套接字代替IPC,从而简化以后向联网的应用程序转移的工作. 
2. 可移植性. 
3. 性能,在具体的开发环境下运行测试程序,比较几种IPC的性能差异. 
4. 实时调度.如果需要这一特性,而且所用的系统也支持posix实时调度选项,那就考虑使用Posix的消息传递和同步函数. 


2 1