zoukankan      html  css  js  c++  java
  • Linux 进程间通信 无名管道(pipe)

    无名管道

    1)只能用于具有亲缘关系的进程之间的通信(无名管道是某一个进程创建的,不像普通文件有路径,在文件系统中是不可见的,其他进程要想打开,只能通过继承的方式去打开)

    2)半双工的通信模式,具有固定的读端和写端

    3)管道可以看成是一种特殊的文件,对于它的读写可以使用文件IO如read、write函数。

    4)管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。其中fd[0]固定用于读管道,而fd[1]固定用于写管道。

    注意事项
    1)当管道中无数据时,读操作会阻塞

    2)管道中有数据,将写端关闭,可以将数据读出

    3)管道中无数据,将写端关闭,读操作会立即返回

    4)管道中装满数据写阻塞,一旦有4k空间,写继续

    5)只有在管道的读端存在时,向管道中写入数据才有意义。否则,会导致管道破裂,向管道中写入数据的进程将收到内核传来的SIGPIPE信号(通常Broken        pipe错误)。

    6)不管pipe还是FIFO当把读端和写端都关闭的时候,管道存放在内存中的内容都会被自动释放

    7)当用open打开的时候,当只打开读端,或者只打开写端,open会阻塞

    创建无名管道

    int pipe(int pipefd[2]);

     参数:文件描述符 fd[0]:读端 fd[1]:写端

    成功返回 0 ,失败返回 -1

     例子1:管道中没有数据时读操作阻塞

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(int argc, const char *argv[])
    {
        int fd[2];
        char buf[50] = {0};//缓存
    
        if(pipe(fd)!=0)// 创建无名管道
        {
            perror("pipe fail: ");
            exit(1);
        }
        printf("%d %d
    ",fd[0],fd[1]);//打开的文件描述符,此处为3,4 默认打开 0,1,2,标准输入,输出,出错
        //管道中没有数据的时候读阻塞
      //  write(fd[1],"hello",10);  //此处不向管道写数据时,读操作会阻塞,管道中有数据时,读操作后结束进程
        read(fd[0],buf,10);
        printf("%s",buf);
        putchar(10); // '
    '
        return 0;
    }

    测试:读操作一直阻塞

     例子2:管道中有数据,将写端关闭,可以将数据读出

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(int argc, const char *argv[])
    {
        int fd[2];
        char buf[50] = {0};//缓存
        if(pipe(fd)!=0)// 创建无名管道
        {
            perror("pipe fail: ");
            exit(1);
        }
        printf("%d %d
    ",fd[0],fd[1]);//打开的文件描述符,默认打开 0,1,2
        //管道中有数据,写端关闭,可以将数据读出
        write(fd[1],"12349",5); //向管道中写入数据,然后关闭写端
        close(fd[1]);
        read(fd[0],buf,5);
        printf("%s",buf);
        putchar(10); // '
    '
        return 0;
    }

    测试:

    例子3:管道中无数据,将写端关闭,读操作会立即返回

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(int argc, const char *argv[])
    {
        int fd[2];
        char buf[50] = {0};//缓存
        if(pipe(fd)!=0)// 创建无名管道
        {
            perror("pipe fail: ");
            exit(1);
        }
        printf("%d %d
    ",fd[0],fd[1]);//打开的文件描述符,默认打开 0,1,2
        //写端关闭,管道中无数据,读操作立即返回
        close(fd[1]);
        read(fd[0],buf,5);
    
        return 0;
    }

    测试:管道中无数据,写端关闭,读操作直接返回

     

     例子4:管道大小 64K 

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(int argc, const char *argv[])
    {
        int fd[2];
        char buf[50] = {0};//缓存
        if(pipe(fd)!=0)// 创建无名管道
        {
            perror("pipe fail: ");
            exit(1);
        }
        printf("%d %d
    ",fd[0],fd[1]);//打开的文件描述符,默认打开 0,1,2
        //管道大小 64k
        int num = 0;
        ssize_t size;
        while(1) //循环一直运行,当写入 64K 后悔阻塞
        {
            size = write(fd[1],"123",1024);
            printf("size = %ld
    ",size);  //每次写入1024个字节,即 1K ,此次编译会警告
            num++;
            printf("num = %d
    ",num);
        }
        return 0;
    }

    测试:

     

    警告类型不匹配

     例子5: 管道中装满数据写阻塞,一旦有4k空间,写继续

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    //int pipe(int pipefd[2]);
    
    int main(int argc, const char *argv[])
    {
        int fd[2];
    
        char buf_w[65536] = {0}; //一次写入 64K 数据
        char buf_r[4096] = {0};  //一次读出 4K 数据
    
        if(pipe(fd)!=0)// 创建无名管道
        {
            perror("pipe fail: ");
            exit(1);
        }
    
        printf("%d %d
    ",fd[0],fd[1]);//打开的文件描述符,默认打开 0,1,2
    
    
        //管道中装满数据写阻塞,一旦有 4k, 才可以继续进行写操作
        write(fd[1],buf_w,65536);//一次写入 64k
    //    read(fd[0],buf_r,4096); //一次读出4k,在进行写操作 ,程序直接结束
        read(fd[0],buf_r,4095); //一次读出 4k-1,在进行写操作  ,此时运行程序阻塞
        write(fd[1],"a",1); // 先读出 4K 数据在写一个字符,或者读4K - 1 个字符,在进行写操作
    
        return 0;
    }

    测试:当读出 4K 数据时可以正常写入,当读出 4K-1 数据时 程序阻塞

  • 相关阅读:
    Jenkins系列之二——centos 6.9 + JenKins 安装
    查看linux系统是运行在物理机还是虚拟机方法
    Java 的不可变类 (IMMUTABLE CLASS) 和 可变类 (MUTABLE CLASS)
    Java中的mutable和immutable对象实例讲解
    理解Java中的引用传递和值传递
    深入理解Java中的Clone与深拷贝和浅拷贝
    java Clone使用方法详解
    Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
    赏美-第[001]期-20190504
    赏美-第[000]期
  • 原文地址:https://www.cnblogs.com/electronic/p/10939995.html
Copyright © 2011-2022 走看看