管道、消息队列、共享内存之间的区别与联系

原创 2016年08月30日 16:40:03

管道和消息队列的区别


管道(PIPE)

     管道通信方式的中间介质是文件,通常称这种文件为管道文件。两个进程利用管道文件进行通信时,一个进程为写进程,另一个进程为读进程。写进程通过写端(发送端)往管道文件中写入信息;读进程通过读端(接收端)从管道文件中读取信息。两个进程协调不断地进行写、读,便会构成双方通过管道传递信息的流水线。


管道分为匿名管道和命名管道。

(1)匿名管道:管道是半双工的,数据只能单向通信;需要双方通信时,需要建立起两个管道;只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)。

(2)命名管道:可在同一台计算机的不同进程之间或在跨越一个网络的不同计算机的不同进程之间,支持可靠的、单向或双向的数据通信


      不同于匿名管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。


     利用系统调用pipe()创建一个无名管道文件,通常称为无名管道或PIPE;利用系统调用mknod()创建一个命名管道文件,通常称为有名管道或FIFO。PIPE是一种非永久性的管道通信机构,当它访问的进程全部终止时,它也将随之被撤消;它也不能用于不同族系的进程之间的通信。而FIFO是一种永久的管道通信机构,它可以弥补PIPE的不足。管道文件被创建后,使用open()将文件进行打开,然后便可对它进行读写操作,通过系统调用write()和read()来实现。通信完毕后,可使用close()将管道文件关闭。因为匿名管道的文件是内存中的特殊文件,而且是不可见的,命名管道的文件是硬盘上的设备文件,是可见的。




消息队列(message queue)

      消息队列与命名管道类似,但少了打开和关闭管道方面的复杂性。使用消息队列并未解决我们在使用命名管道时遇到的一些问题,如管道满时的阻塞问题。消息队列提供了一种在两个不相关进程间传递数据的简单有效的方法。与命名管道相比:消息队列的优势在于,它独立于发送和接收进程而存在,这消除了在同步命名管道的打开和关闭时可能产生的一些困难。消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。而且,每个数据块被认为含有一个类型,接收进程可以独立地接收含有不同类型值的数据块。


优点:
      A. 我们可以通过发送消息来几乎完全避免命名管道的同步和阻塞问题。
      B. 我们可以用一些方法来提前查看紧急消息。

缺点:
      A. 与管道一样,每个数据块有一个最大长度的限制。
      B. 系统中所有队列所包含的全部数据块的总长度也有一个上限。

Linux系统中有两个宏定义:
 MSGMAX, 以字节为单位,定义了一条消息的最大长度。
 MSGMNB, 以字节为单位,定义了一个队列的最大长度。

限制:
      由于消息缓冲机制中所使用的缓冲区为共用缓冲区,因此使用消息缓冲机制传送数据时,两通信进程必须满足如下条件。
     (1)在发送进程把写入消息的缓冲区挂入消息队列时,应禁止其他进程对消息队列的访问,否则,将引起消息队列的混乱。同理,当接收进程正从消息队列中取消息时,也应禁止其他进程对该队列的访问。
     (2)当缓冲区中无消息存在时,接收进程不能接收任何消息;而发送进程是否可以发送消息,则只由发送进程是否能够申请缓冲区决定。



=============================================================================================

共享内存比管道和消息队列效率高的原因

    共享内存是进程间通信中最简单的方式之一。共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针。当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。

    因为所有进程共享同一块内存,共享内存在各种进程间通信方式中具有最高的效率。访问共享内存区域和访问进程独有的内存区域一样快,并不需要通过系统调用或者其它需要切入内核的过程来完成。同时它也避免了对数据的各种不必要的复制。
    因为系统内核没有对访问共享内存进行同步,您必须提供自己的同步措施。例如,在数据被写入之前不允许进程从共享内存中读取信息、不允许两个进程同时向同一个共享内存地址写入数据等。解决这些问题的常用方法是通过使用信号量进行同步。

    共享内存块提供了在任意数量的进程之间进行高效双向通信的机制。每个使用者都可以读取写入数据,但是所有程序之间必须达成并遵守一定的协议,以防止诸如在读取信息之前覆写内存空间等竞争状态的出现。不幸的是,Linux无法严格保证提供对共享内存块的独占访问,甚至是在您通过使用IPC_PRIVATE创建新的共享内存块的时候也不能保证访问的独占性。 同时,多个使用共享内存块的进程之间必须协调使用同一个键值。     


       共享内存区是最快的可用IPC形式,一旦这样的内存区映射到共享它的进程的地址空间,这些进程间数据的传递就不再通过执行任何进入内核的系统调用来传递彼此的数据,节省了时间。
       共享内存和消息队列,FIFO,管道传递消息的区别:
       ——消息队列,FIFO,管道的消息传递方式一般为
          1:服务器得到输入
          2:通过管道,消息队列写入数据,通常需要从进程拷贝到内核。
          3:客户从内核拷贝到进程
          4:然后再从进程中拷贝到输出文件
      上述过程通常要经过4次拷贝,才能完成文件的传递。
       ——共享内存只需要
           1:从输入文件到共享内存区
           2:从共享内存区输出到文件

上述过程不涉及到内核的拷贝,所以花的时间较少。




版权声明:本文为博主原创文章,未经博主允许不得转载。

linux 管道、消息队列、共享内存的对比

------管道 管道的优点是不需要加锁,缺点是默认缓冲区太小,只有4K,同时只适合父子进程间通信,而且一个管道只适合单向通信,如果要双向通信需要建立两个。而且不适合多个子进程,因为消息会乱,它的发送...
  • piaoairy219
  • piaoairy219
  • 2013年12月15日 14:36
  • 7527

进程间通讯的消息队列和共享内存方式的实现

qt,进程间通讯,消息传递模式,共享内存模式
  • zhangxufei
  • zhangxufei
  • 2016年02月18日 15:29
  • 2077

利用共享内存实现消息队列

日历登录管理器 利用共享内存实现消息队列   2009-02-28 22:02:44|  分类: Windows |  标签: |举报 |字号大中小 订阅 ...
  • flyingleo1981
  • flyingleo1981
  • 2014年05月24日 17:11
  • 1373

linux消息队列的内核限制

消息队列: 1.每次msgrcv一个消息,1.那个消息会在内核中移除 2.每次msgrcv都只会给一个消息出来,不管你rcv用多大的buf来接收,都是可以的。如果msgrcv的bufSize小于...
  • cwj649956781
  • cwj649956781
  • 2013年04月15日 17:28
  • 17294

消息队列的设置

/etc/sysctl.conf 修改 kernel.msgmni=1000 kernel.msgmax=81920 kernel.msgmnb=163840 MSGMNB 每个消息队...
  • leinchu
  • leinchu
  • 2012年11月07日 18:05
  • 1676

DB2 最佳实践: 性能调优和问题诊断最佳实践

最佳实践的相关文章可见:http://www.ibm.com/developerworks/cn/data/bestpractices/ DB2 最佳实践: 性能调优和问题诊断最佳实...
  • pianzif
  • pianzif
  • 2014年06月16日 16:45
  • 2426

共享内存+信号量+消息队列实现IPC

一组服务器与客户端之间通信方式有很多,下面介绍一种共享内存+信号量+消息队列的形式来实现进程间的通信。 信号量:信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于...
  • qq_29214249
  • qq_29214249
  • 2016年09月08日 17:35
  • 433

用sysctl调整linux内核参数

sysctl是一个允许您改变正在运行中的Linux系统的接口。它包含一些 TCP/IP 堆栈和虚拟内存系统的高级选项, 这可以让有经验的管理员提高引人注目的系统性能。用sysctl可以读取设置超过五百...
  • bb6lo
  • bb6lo
  • 2015年07月17日 16:31
  • 1727

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

进程间通信的方式有很多,常见的有信号,信号量,消息队列,管道,共享内存,和socket等,这里我们主要讨论管道,共享内存,和socket,其他的比较简单只做简单的介绍。 信号:信号主要用于通知某个进程...
  • D_Guco
  • D_Guco
  • 2016年12月08日 21:14
  • 6682

进程间通信方式总结——管道(一)

Linux/Unix系统IPC是各种进程间通信方式的统称,但是其中极少能在所有Linux/Unix系统实现中进行移植。随着POSIX和Open Group(X/Open)标准化的推进呵护影响的扩大...
  • tf_apologize
  • tf_apologize
  • 2017年04月13日 16:28
  • 483
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:管道、消息队列、共享内存之间的区别与联系
举报原因:
原因补充:

(最多只允许输入30个字)