Linux 之 pipe管道

Linux 之 pipe管道

前言

Linux下有很多IPC机制,pipe管道就是其中的一种。

正文

管道的概念

pipe被称为无名管道,用于亲缘进程间的通信。pipe管道实质为一个内核维护的环形队列,缓冲区大小为4K。工作方式为半双工通信。调用 pipe函数可以创建一个管道。
函数原型:
#include <unistd.h>
int pipe(int fd[2]);
管道有读写两端,fd[0]为读端,fd[1] 为写端。对于一个进程来说,要么对管道进行读操作,要么对其进行写操作,不可以自己写,自己读,所以当一个进程对管道进行写操作之前先关闭其读端,反之亦然。

父写子读

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
int main()
{
    
     
        int fd[2];
        if(pipe(fd) == -1)
        {
    
    
         perror("管道打开失败:");
         exit(-1);
        }
        pid_t id = fork();
        if(id == -1)
        {
    
    
         perror("进程创建失败:");
         exit(-1);
        }
        else if(id == 0) //子进程
        {
    
    
          close(fd[1]);
          char buf[100];
          memset(buf,0,sizeof(buf));
          int re = read(fd[0],buf,sizeof(buf));
          if(re == 0)
                  exit(-1);
          else
                  printf("子进程读入成功: %s\n",buf);
        }
        else // 父进程
        {
    
    
         close(fd[0]);
         int re = write(fd[1],"hello world",12);
         if(re == 0)
         {
    
    
          printf("父进程写入失败\n");
          exit(-1);
         }
          printf("父进程写入成功\n");
          sleep(1);
        }
}
                                         

输出结果:
父进程写入成功
子进程读入成功: hello world

对于管道的读写:
1.当写端被全部关闭(计数为0),对管道进行读操作,如果其中有数据,会正常读出,直到管道为空,再进行读操作,read返回0。
2.当写端没全部关闭,对管道进行读操作,若管道中无数据,read会阻塞。
3.当读端被全部关闭,读其进行写操作,进程会收到信号SIGPIPE,导致进程异常终止。
4.当读端没被全部关闭,对管道进行写操作,管道缓冲区剩余内存无法将本次内容全部写入,会阻塞到有足够空间才进行写入。

一端写多端读

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
int main()
{
    
    
        int fd[2];
        if(pipe(fd) == -1)
        {
    
    
         perror("管道打开失败:");
         exit(-1);
        }
        pid_t id;
       for(int i=0;i<2;i++)
       {
    
    
         id = fork();
         if(id == 0)
                 break;

        if(id == -1)
        {
    
    
         perror("进程创建失败:");
         exit(-1);
        }
       }
        if(id == 0) //子进程
        {
    
    
          close(fd[1]);
          char buf[100];
          memset(buf,0,sizeof(buf));
          int re = read(fd[0],buf,12);
          if(re == 0)
                  exit(-1);
          else
                  printf("子进程读入成功: %s\n",buf);
        }
        else // 父进程
        {
    
     
        close(fd[0]);
        int re;
        for(int i=0;i<2;i++)
        {
    
    
         re = write(fd[1],"hello world",12);
         if(re == 0)
         {
    
    
          printf("父进程写入失败\n");
          exit(-1);
         }
          printf("父进程写入成功\n");
        }
          sleep(1);
        }
}

输出结果:
父进程写入成功
父进程写入成功
子进程读入成功: hello world
子进程读入成功: hello world

一端读多端写

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
int main()
{
    
    
        int fd[2];
        if(pipe(fd) == -1)
        {
    
    
         perror("管道打开失败:");
         exit(-1);
        }
        pid_t id;
       for(int i=0;i<2;i++)
       {
    
    
         id = fork();
         if(id == 0)
                 break;

        if(id == -1)
        {
    
    
         perror("进程创建失败:");
         exit(-1);
        }
       }
        if(id != 0) //父进程
        {
    
    
          close(fd[1]);
          char buf[100];
          memset(buf,0,sizeof(buf));
         for(int i=0;i<2;i++)
         {
    
    
          int re = read(fd[0],buf,12);
          if(re == 0)
                  exit(-1);
          else
                  printf("父进程读入成功: %s\n",buf);
        }
         }
        else // 子进程
        {
    
    
         close(fd[0]);
         int re;
         re = write(fd[1],"hello world",12);
         if(re == 0)
         {
    
    
          printf("子进程写入失败\n");
          exit(-1);
         }
          printf("子进程写入成功\n");
        }


}

输出结果:
子进程写入成功
父进程读入成功: hello world
子进程写入成功
父进程读入成功: hello world

管道的限制

1.只能作用于亲缘进程之间。
2.不能自己写自己读。
3.一旦读出后,数据就不会存在于管道中。
4.数据只能在一个方向上流动。

猜你喜欢

转载自blog.csdn.net/weixin_45074185/article/details/108210106