本文主要是介绍进程间的通讯--管道(有名、无名),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
进程间的通讯–管道(有名、无名)
管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。(无名管道)
【命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。】
管道
1、特点:
-
它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
-
它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)无名管道只适用于父子进程间通信,有名管道可以再任何进程之间通讯
-
它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
-
管道分为pipe(无名管道)和fifo(命名管道)两种,除了建立、打开、删除的方式不同外,这两种管道几乎是一样的。他们都是通过内核缓冲区实现数据传输。
pipe用于父进程和子进程之间的通讯,它通过pipe()系统调用来创建并打开,当最后一个使用它的进程关闭对他的引用时,pipe将自动撤销。
FIFO即命名管道,在磁盘上有对应的节点,但没有数据块——换言之,只是拥有一个名字和相应的访问权限,通过mknode()系统调用或者mkfifo()函数来建立的。一旦建立,任何进程都可以通过文件名将其打开和进行读写,而不局限于父子进程,当然前提是进程对FIFO有适当的访问权。当不再被进程使用时,FIFO在内存中释放,但磁盘节点仍然存在。
管道的实质是一个内核缓冲区,进程以先进先出的方式从缓冲区存取数据:管道一端的进程顺序地将进程数据写入缓冲区,另一端的进程则顺序地读取数据,该缓冲区可以看做一个循环队列,读和写的位置都是自动增加的,一个数据只能被读一次,读出以后再缓冲区都不复存在了。当缓冲区读空或者写满时,有一定的规则控制相应的读进程或写进程是否进入等待队列,当空的缓冲区有新数据写入或慢的缓冲区有数据读出时,就唤醒等待队列中的进程继续读写。
无名管道: 父进程创建管道,并在管道中写入数据,而子进程从管道读出数据
仅仅适用于具有亲缘关系(如父子进程)的进程间通信,因为匿名管道无法被其他进程找到,也就无法通信,所以只能通过子进程复制父进程的方法,让子进程能够访问到相同的管道来实现通信。(管道的操作:io操作------文件描述符)
特点:
1、使用条件:只能用于具有亲缘关系(父子进程,兄弟进程等)的进程之间的通信2、通信模式:半双工模式,fd[0]作为读端,fd[1]作为写端3、读写方式:对于它的读写采用文件IO(不支持lseek函数)4、读操作会阻塞(等待):在管道中无数据情况下。写操作会阻塞(等待):当管道被写满时,无名管道的大小为64K如果所有管道写入端关闭,read读完所有数据之后返回0;如果所有管道读取端关闭,write将触发异常,操作系统此时会发送SIGPIPE信号,通知我们读取端都被关闭了。(这个信号会导致write端进程退出)。 5、管道破裂:管道读端关闭,再向管道中写数据时。
注意: 接口:pipe(int fd[2]),其中fd[1]用于读,fd[2]用于写。创建匿名管道必须在创建子进程之前,否则子进程将无法复制。
有名管道:
和无名管道的主要区别在于,命名管道有一个名字,命名管道的名字对应于一个磁盘索引节点,有了这个文件名,任何进程有相应的权限都可以对它进行访问。
- 创建:mkfifo- 读写特性:与匿名管道相同。- 匿名管道是已经直接打开了,pipe接口直接返回的文件描述符,命名管道创建之后并不会直接打开,需要我们用户自己open打开来进行后续操作。- 如果没有一方以写的方式打开,那么以读的方式打开时就会阻塞;- 如果没有一方以读的方式打开,那么以写的方式打开时就会阻塞。- 如果以读写方式打开,则不会阻塞
注意:FIFO不同于无名管道之处在于它提供了一个路径名与之关联,以FIFO的文件形式存在于文件系统中,这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信,因此,通过FIFO不相关的进程也能交换数据。值的注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。
mainA.c 读端:
mainB.c 写端:
执行结果:
这篇关于进程间的通讯--管道(有名、无名)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!