管道pipe体现了python 进程中pipe之间一种怎样的关系

c/c++ linux编程(5)
&& 在linux系统中,管道是一种特殊的文件,它的主要作用是实现进程间的通信。
&& 管道的一个显著特点是:当一个管道建立后,将获得两个文件描述符,分别用于对管道读取和写入,通常将其称为管道的写入端和读取端,从写入端写入管道的任何数据都可以从读取端读取。对于一个进程来说,管道的写入和读取操作与写入和读取一个普通文件没有区别,只是在内核中通过这种机制来实现进程间的通信。
& 管道的局限性:
&1,管道只能用于两个进程间的通信,不能用与多个(&3)进程间的通信。
&2,这两个进程要有同源性,即他们必须是最终由同一个进程所派生的进程。
&3,管道是半双工方式的,即只允许单向传输数据。
创建pipe管道函数:
int pipe(int file_descriptor[2]);
函数pipe填充的两个整数的含义是两个文件描述符,任何向file_descriptor[1](写入端)写入的数据,可以从file_descriptor[0](读取端)中读取,并且写入的数据符合先入先出的规则.
* =====================================================================================
Description:
日 14时21分11秒
MaZheng (blog.csdn.net/mazheng1989),
Dalian University Of Technology
* =====================================================================================
#include&stdio.h&
#include &unistd.h&
#include &string.h&
#include &sys/types.h&
#include &stdlib.h&
int main()
int file_pipes[2];
const char some_data[]=&123&;
char buffer[BUFSIZ+1];
memset(buffer,'\0',sizeof(buffer));
if(pipe(file_pipes)==0){
fork_result=fork(); /* 设置进程 */
if (fork_result==-1){
/* 判断设置进程是否出错 */
fprintf(stderr,&Fork failure&);
/* 下面判断,若是是子进程则读管道数据,父进程则向管道写数据 */
if(fork_result==0){
/* 判断是否子进程 */
data_processed=read(file_pipes[0],buffer,BUFSIZ);
/* 从管道读数据 */
close(file_pipes[1]);
printf(&Read %d bytes:%s\n&,data_processed,buffer);
/* 父进程 */
data_processed=write(file_pipes[1],some_data,strlen(some_data));
/* 向管道写数据 */
close(file_pipes[0]);
printf(&Wrote %d bytes\n&,data_processed);
程序运行:./pipe
Wrote 3 bytes
Read 3 bytes:123
利用管道进行通信成功!
里面的例子:
#include &sys/wait.h&
#include &stdio.h&
#include &stdlib.h&
#include &unistd.h&
#include &string.h&
main(int argc, char *argv[])
int pipefd[2];
if (argc != 2) {
fprintf(stderr, &Usage: %s &string&\n&, argv[0]);
exit(EXIT_FAILURE);
if (pipe(pipefd) == -1) {
perror(&pipe&);
exit(EXIT_FAILURE);
cpid = fork();
if (cpid == -1) {
perror(&fork&);
exit(EXIT_FAILURE);
if (cpid == 0) {
/* Child reads from pipe */
close(pipefd[1]);
/* Close unused write end */
while (read(pipefd[0], &buf, 1) & 0)
write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, &\n&, 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
/* Parent writes argv[1] to pipe */
close(pipefd[0]);
/* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]);
/* Reader will see EOF */
wait(NULL);
/* Wait for child */
exit(EXIT_SUCCESS);
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:130393次
积分:2355
积分:2355
排名:第12562名
原创:103篇
转载:12篇
评论:76条
(1)(1)(4)(9)(1)(12)(10)(2)(15)(51)(10)Linux进程间通信方式之管道(pipe)
Linux进程间通信方式之管道(pipe)
发布时间: 19:02:58
编辑:www.fx114.net
本篇文章主要介绍了"Linux进程间通信方式之管道(pipe)",主要涉及到Linux进程间通信方式之管道(pipe)方面的内容,对于Linux进程间通信方式之管道(pipe)感兴趣的同学可以参考一下。
进程间通信
每个进程各自有独立的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,但是所有进程都共享内核地址空间,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,Inter&Process&Communication)。如下图所示。
管道是Linux&支持的最初Unix&IPC形式之一,具有以下特点:
1)&管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
2)&匿名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
3)&单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
一个管道实际上就是个只存在于内存中的文件,根据管道的适用范围将其分为:无名管道和命名管道。
1.&无名管道
主要用于父进程与子进程之间,或者两个兄弟进程之间。在Linux系统中可以通过系统调用建立起一个单向的通信管道,且这种关系只能由父进程来建立。因此,每个管道都是单向的,当需要双向通信时就需要建立起两个管道。管道两端的进程均将该管道看做一个文件,一个进程负责往管道中写内容,而另一个从管道中读取。这种传输遵循“先入先出”(FIFO)的规则。
2.&命名管道
命名管道是为了解决无名管道只能用于近亲进程之间通信的缺陷而设计的。命名管道是建立在实际的磁盘介质或文件系统(而不是只存在于内存中)上有自己名字的文件,任何进程可以在任何时间通过文件名或路径名与该文件建立联系。为了实现命名管道,引入了一种新的文件类型——FIFO文件(遵循先进先出的原则)。实现一个命名管道实际上就是实现一个FIFO文件。命名管道一旦建立,之后它的读、写以及关闭操作都与普通管道完全相同。虽然FIFO文件的inode节点在磁盘上,但是仅是一个节点而已,文件的数据还是存在于内存缓冲页面中,和普通管道相同。
无名管道的创建
int pipe(int fd[2])
调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端和一个写端,然后通过fd参数传出给用户程序两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端(很好记,就像0是标准输入1是标准输出一样)。所以管道在用户程序看起来就像一个打开的文件,通过read(fd[0])或者write(fd[1])向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返回-1。
管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为1页,即4K字节。如果一次write调用写的数据量小于管道容量,则写必须一次完成,如果管道所剩余的容量不够,同时管道写端口被设置为阻塞方式,write被阻塞,等待某些数据被读取,直到管道的剩余容量可以一次写完为止。如果write调用写的数据量大于管道容量,则写操作分多次完成。如果用fcntl设置管道写端口为非阻塞方式,则管道满不会阻塞写,而只是对写返回0。
读操作按数据到达的顺序读取数据。已经被读取的数据在管道内不再存在,这意味着数据在管道中不能重复利用。如果管道为空,且管道的写端口是打开状态,则读操作被阻塞直到有数据写入为止。一次read调用,如果管道中的数据量不够read指定的数量,则按实际的数量读取,并对read返回实际数量&值。如果读端口使用fcntl设置了非阻塞方式,则当管道为空时,read调用返回0。
如果管道的读端口关闭,那么在该管道上的发出写操作调用的进程将接收到一个SIGPIPE信号。关闭写端口是给读端口一个文件结束符的唯一方法。对于写端口关闭后,在该管道上的read调用将返回0。
环形缓冲区
每个管道只有一个页面作为缓冲区,该页面是按照环形缓冲区的方式来使用的。这种访问方式是典型的“生产者——消费者”模型。当“生产者”进程有大量的数据需要写时,而且每当写满一个页面就需要进行睡眠等待,等待“消费者”从管道中读走一些数据,为其腾出一些空间。相应的,如果管道中没有可读数据,“消费者”进程就要睡眠等待,具体过程如下图所示。
环形缓冲区是嵌入式系统中一个常用的重要数据结构。一般采用数组形式进行存储,即在内存中申请一块连续的线性空间,可以在初始化的时候把存储空间一次性分配好。只是要模拟环形,必须在逻辑上把数组的头尾相连接。只要对数组最后一个元素进行特殊的处理——访问尾部元素的下一元素时,重新回到头部元素。对于从尾部回到头部只需模缓冲长度即可(假设maxlen为环形缓冲的长度,当读指针read指向尾部元素时,只需执行read=read%maxlen即可使read回到头部元素)。
进程间通信
开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信:
本文标题:
本页链接:Linux 进程间通讯方式 pipe()函数 - 推酷
Linux 进程间通讯方式 pipe()函数
Linux 进程间通讯方式有以下几种:
1-》管道(pipe)和有名管道(fifo).
2-》消息队列
3-》共享内存
4-》信号量
5-》信号(signal)
6-》套接字(sicket)
在这里我们看一下第一种====管道(pipe)。有名管道(fifo)见其它文章。
eg :我们以前学的命令 cat& file | grep& &abc&& & file2
在我看来 我们把cat 读取file中的内容读到内存在通过过滤命令grep 过滤出包含&abc&的记录 再输出重定向到文件file2
在这个过程中 我们把cat& file | grep& &abc&的输出内容作为 & 的输入内容。
在Linux系统中,管道通信可以通过使用系统调用来实现。
使用格式为:
#include&unistd.h&
int& pipe(int fd[2]);
功能: 创建一个简单的管道,若成功则为数组fd分配两个文件描述符,其中fd[0] 用于读取管道,fd[1]用于写入管道。
返回:成功返回0,失败返回-1;
管道,顾名思义,当我们希望将两个进程的数据连接起来的时候就可以使用它,从而将一个进程的输出数据作为另一个进程的输入数据达到
通信交流的目的。
但值得我们注意的是:管道它有自身的特点。
&(1)管道通信是单向的,并且遵守先进先出的原则,即先写入的数据先读出。
&(2)管道是一个无结构,无固定大小的字节流。
&(3) 管道把一个进程的标准输出和另一个进程的标准输入连接在一起。数据读出后就意味着从管道中移走了,消失了。其它的进程都不能&&&
&&&&&&&&&& 再读到这些数据。就像我们平常见到的管子水流走了就没有了。 这点很重要!!
& (4) pipe这种管道用于两个有亲缘关系的进程之间。eg:父子进程......
好了,废话不多说了,下面我们看个例子:come on
#include&stdio.h&
#include&unistd.h&
#include&stdlib.h&
#include&string.h&
#include&wait.h&
#include&sys/types.h&
int main(int argc ,char *argv[])
&int pipefd[2],
&char buf[1024];
&int flag=0;
&result= pipe(pipefd);//创建一个管道
&if(result==-1){
&&perror(&pipe error:&);
&&exit(EXIT_FAILURE);
&pid=fork();//创建一个子进程
&if(pid==-1)
&&perror(&fork& error:&);
&&exit(EXIT_FAILURE);
&else if(pid==0){
&&if((close(pipefd[1]))==-1)//close write only read
&&&perror(&close write& error:&);
&&&exit(EXIT_FAILURE);
&&while(1){ //循环读取数据
&&&read(pipefd[0],buf,1024);//最多读取1024个字节
&&&printf(&read from pipe :& %s\n&,buf);
&&&if(strcmp(buf,&exit&)==0){// if 读取到的字符串是exit 这是
&&&&&&&&&&&&&&&&&&& //父进程会接受到一个终止进程的信号,父进程会回收子进程的资&&&&&&&&&&&&&&&&&& // 源等
&&&exit(EXIT_SUCCESS);
&&//close read only write
&&if((close(pipefd[0]))==-1){
&&&perror(&close read error:&);
&&&exit(EXIT_FAILURE);
&&while(1)//循环写入内容
&&&waitpid(pid,NULL,WNOHANG);//等待子进程退出
&&&if(flag==1)
&&&&exit(0);
&&&scanf(&%s&,buf);
&&&write(pipefd[1],buf,strlen(buf)+1);//具体写多少个字节
&&&if(strcmp(buf,&exit&)==0){
&&&&flag=1;
&&&&sleep(1);//让子进程完全退出。
&return 1;
此程序代码中都有注释,在这里就不废话了。
运行结果为:
当我们键入exit时 父子进程都退出。
此时我们可以用ps -aux进行查看。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致pipe/fifo 管道与有名管道
1. 管道用于有血缘关系的进程之间的通信。
2. fifo可用于任意进程之间的通信,fifo在的文件系统内有一个名字。虽然FIFO在文件系统中有一个路经名,但对FIFO的IO操作不会涉及到底层的设备。
3. pipe与fifo的不同仅仅在于打开和创建的方式上,在其它的方面两者没有区别。因此下面的描述对两者都适用。
4. 如果一个进程试图读一个空管道,read 函数将会阻塞直到数据到来。如果一个进程写一个full管道,write函数将会阻塞直到有足够多的数据从管道读出,从而使得write操作能够完成。(第4条都是没有设置O_NONBLOCK的条件下的情形)
5. 管道提供的是字节流通信,没有任何消息边界的概念。
6. 如果一个管道的所有写端都已经关闭,则读管道将会得到一个文件结束符(read将支返回0).如果一个管道的所有读端都已经关闭,则写管道将会收到一个 SIGPIPE 信号。
7. 管道没有lseek操作
8. 管道容量: 一个管道的容量是有限的。POSIX规定少于 PIPE_BUF 的写操作必须原子完成:要写的数据应被连续的写到管道。大于 PIPE_BUF 的写操作可能是非原子的: 内核可能会把此数据与其它进程的对此管道的写操作交替起来。POSIX规定PIPE_BUF至少为512B(linux中为4096B)& 具体的语义如下: 其中n为要写的字节数.
&&& * n &= PIPE_BUF, O_NONBLOCK无效:原子的写入n个字节。如果管道当前的剩余空间不足以立即写入n个字节,就阻塞直到有足够的空间。
&&& * n &= PIPE_BUF, O_NONBLOCK有效:如果有足够的空间写入n个字节,write立即成功返回。否则write失败,并设置errno为EAGAIN& (此时没有写入字节).
&&& * n && PIPE_BUF, O_NONBLOCK无效:非原子写。可能会和其它的写进程交替写。write阻塞直到将n个字节写入管道。
&&& * n && PIPE_BUF, O_NONBLOCK有效:如果管道满,write失败,并将errno设置为 EAGIN。
如果管道不满,依次写入这n个字节(可能会出现&部分写&,调用者应该检查write的返回值来判断实际写入了多少字节),可能会和其它的进程交替写。
9. 对管道来说,只有两个状态标志有有意义的: O_NONBLOCK& O_ASYNC
&&& O_ASYNC: 如果对管道的读端描述符设置了此标志,当有新的数据写入管道的时候,会产生信号(默认是SIGIO)
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'2136人阅读
杂项(70)
使用C语言在UNIX中使用pipe(2)系统调用时,这个函数会让系统构建一个匿名管道,这样在进程中就打开了两个新的,打开的文件描述符:一个只读端和一个只写端。管道的两端是两个普通的,匿名的文件描述符,这就让其他进程无法连接该管道。&
gcc pipe.c
#include &stdio.h&
#include &stdlib.h&
#include &unistd.h&
#define COUNT (10)
int main(int argc, char *argv[])  
  int pipefd[2];  
  int read_count = 0;
  char buf[COUNT] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};;  
  if (pipe(pipefd) == -1) {  
    perror(&call pipe failed \n&);  
    exit(EXIT_FAILURE);  
  }  
  printf(&write %d chars to pipe1 \n&, COUNT);
  write(pipefd[1], buf, COUNT);  
  while (read(pipefd[0], &buf, 1) & 0) 
    printf(&read %c from pipe0\n&, buf[0]);
    read_count++;
    if(read_count == COUNT)
    {
      printf(&total read %d chars \n&, read_count);
     
    }  
  } 
  close(pipefd[0]);  
  close(pipefd[1]);  
编译及执行结果:
[root@alexs-centos core_dump]# gcc pipe.c&
[root@alexs-centos core_dump]# ./a.out&
write 10 chars to pipe1&
read 0 from pipe0
read 1 from pipe0
read 2 from pipe0
read 3 from pipe0
read 4 from pipe0
read 5 from pipe0
read 6 from pipe0
read 7 from pipe0
read 8 from pipe0
read 9 from pipe0
total read 10 chars&
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:776341次
积分:7879
积分:7879
排名:第1966名
原创:89篇
转载:105篇
评论:118条
(1)(2)(3)(3)(3)(2)(1)(2)(4)(2)(1)(1)(3)(4)(1)(2)(1)(2)(3)(2)(1)(1)(5)(3)(1)(1)(1)(1)(6)(2)(2)(5)(3)(1)(5)(4)(2)(1)(4)(2)(1)(3)(5)(4)(1)(1)(3)(1)(2)(2)(1)(1)(6)(2)(2)(1)(5)(1)(3)(2)(3)(4)(2)(3)(1)(1)(2)(5)(5)(5)(17)(2)(1)(1)(3)}

我要回帖

更多关于 进程通信 pipe 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信