linux下进程间通信的总结
1. 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
2. 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数);
3. 报文(Message)队列(消息队列):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
4. 共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
切换到MarkDown编辑器
5. 信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
6. 套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。
对几种IPC的简单比较:
1. 管道,速度较慢,缓冲区大小受限,只能承载无格式的字节流。只能用于有亲缘关系的进程。
2. FIFO管道,任何进程间都可以通信,包括不同机器上的管道,速度较慢。
3. 消息队列:因为位于内核中,所以容量受限,第一次读取时要注意上次添加的消息是否读取。
4. 信号量:不能传递复杂的消息,只用于同步信息。
5. 共享内存:能很容易的控制变量,速度快,要注意读写安全性,避免死锁等。
一。管道(pipe)
管道是Linux支持的最初IPC方式,管道可分为无名管道,有名管道等。
(一)无名管道,它具有几个特点:
1) 管道是半双工的,只能支持数据的单向流动;两进程间需要通信时需要建立起两个管道;
2) 无名管道使用pipe()函数创建,只能用于父子进程或者兄弟进程之间;
3) 管道对于通信的两端进程而言,实质上是一种独立的文件,只存在于内存中;
4) 数据的读写操作:一个进程向管道中写数据,所写的数据添加在管道缓冲区的尾部;另一个进程在管道中缓冲区的头部读数据。
(二)有名管道
有名管道也是半双工的,不过它允许没有亲缘关系的进程间进行通信。具体点说就是,有名管道提供了一个路径名与之进行关联,以FIFO(先进先出)的形式存在于文件系统中。这样即使是不相干的进程也可以通过FIFO相互通信,只要他们能访问已经提供的路径。
值得注意的是,只有在管道有读端时,往管道中写数据才有意义。否则,向管道写数据的进程会接收到内核发出来的SIGPIPE信号;应用程序可以自定义该信号处理函数,或者直接忽略该信号。
二。信号量(semophore)
信号量是一种计数器,可以控制进程间多个线程或者多个进程对资源的同步访问,它常实现为一种锁机制。实质上,信号量是一个被保护的变量,并且只能通过初始化和两个标准的原子操作(P/V)来访问。(P,V操作也常称为wait(s),signal(s))
三。信号(Signal)
信号是Unix系统中使用的最古老的进程间通信的方法之一。操作系统通过信号来通知某一进程发生了某一种预定好的事件;接收到信号的进程可以选择不同的方式处理该信号,一是可以采用默认处理机制-进程中断或退出,一是忽略该信号,还有就是自定义该信号的处理函数,执行相应的动作。
内核为进程生产信号,来响应不同的事件,这些事件就是信号源。信号源可以是:异常,其他进程,终端的中断(Ctrl-C,Ctrl+\等),作业的控制(前台,后台进程的管理等),分配额问题(cpu超时或文件过大等),内核通知(例如I/O就绪等),报警(计时器)。
四。消息队列(Message Queue)
消息队列就是消息的一个链表,它允许一个或者多个进程向它写消息,一个或多个进程向它读消息。Linux维护了一个消息队列向量表:msgque,来表示系统中所有的消息队列。
消息队列克服了信号传递信息少,管道只能支持无格式字节流和缓冲区受限的缺点。
五。共享内存(shared memory)
共享内存映射为一段可以被其他进程访问的内存。该共享内存由一个进程所创建,然后其他进程可以挂载到该共享内存中。共享内存是最快的IPC机制,但由于linux本身不能实现对其同步控制,需要用户程序进行并发访问控制,因此它一般结合了其他通信机制实现了进程间的通信,例如信号量。
六。套接字(socket)
socket也是一种进程间的通信机制,不过它与其他通信方式主要的区别是:它可以实现不同主机间的进程通信。一个套接口可以看做是进程间通信的端点(endpoint),每个套接口的名字是唯一的;其他进程可以访问,连接和进行数据通信。
低级通信主要用于进程之间的同步、互斥、终止、挂起等等控制信息的传递。
高级通信主要用于进程间数据块的交换和共享 常见的高级通信有管道(PIPE)、消息队列(MESSAGE)、共享内存(SHARED MEM0RY)等
三种方式的特点(优缺点):
1.无名管道简单方便.但局限于单向通信的工作方式.并且只能在创建它的进程及其子孙进程之间实现管道的共享:有名管道虽然可以提供给任意关系的进程使用.但是由于其长期存在于系统之中,使用不当容易出错。
2.消息缓冲可以不再局限于父子进程.而允许任意进程通过共享消息队列来实现进程间通信.并由系统调用函数来实现消息发送和接收之间的同步.从而使得用户在使用消息缓冲进行通信时不再需要考虑同步问题.使用方便,但是信息的复制需要额外消耗CPU的时间.不适宜于信息量大或操作频繁的场合。
3.共享内存针对消息缓冲的缺点改而利用内存缓冲区直接交换信息,无须复制,快捷、信息量大是其优点。但是共享内存的通信方式是通过将共享的内存缓冲区直接附加到进程的虚拟地址空间中来实现的.因此,这些进程之间的读写操作的同步问题操作系统无法实现。必须由各进程利用其他同步工具解决。另外,由于内存实体存在于计算机系统中.所以只能由处于同一个计算机系统中的诸进程共享。不方便网络通信。
4.命名管道:常规的管道只能连接相关进程,由进程创建并由最后一个进程关闭。而命名管道可以连接不相关的进程。它是个FIFO先进先出队列,即使没有进程,命名管道依然可以存在,它不依赖于进程。服务器将字节写入队列,客户端从队列头部移出字节。服务器必须重写数据。它没有竞争的问题,在没有超过管道最大长度的时候,read和write都是原子操作,先将管道清空,然后再将管道写满,在读者和写者联通之前系统内核将进程刮起。
5。共享内存段:不依赖于进程的存在而存在。共享内存段拥有权限系统来控制进程各自的访问权限。多个客户端都可以同时从内存中读数据。