zoukankan      html  css  js  c++  java
  • 【linux高级程序设计】(第九章)进程间通信-管道 1

    Linux操作系统所支持的主要进程间的通信机制。

    无名管道 PIPE

    cat test.txt| grep hello

    上面这种管道,将一个命令的输出作为另一个命令的输入,而这种管道是临时的,命令执行完成后将自动消失,称为无名管道。

    int pipe (int __pipedes[2]) :创建无名管道

      如果执行成功,pipe将存储两个整型文件描述符于__pipedes[0](只能读)和__pipedes[1](只能写)中,它们分别指向管道的两端。如果需要双工的,需要建立两个管道。

                           

    读写无名管道

    必须确认还存在一个进程,可以使进程自己。默认以阻塞方式读写管道,如果修改可以使用fcntl函数实现。

    (1)以阻塞方式读取无名管道,且当前没有进程可以访问写端

    • 如果管道现有数据无数据,立即返回0
    • 如果管道现有数据大于要读出的数据,立即读取期望大小的数据
    • 如果管道现有数据小于要读出的数据,立即读取所有数据

    第一种情况

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    
    int main(void)
    {
        int p[2];
        pipe(p);
        close(p[1]);  //断开当前进程与管道写端的联系
        char buf[128];
        memset(buf, '', 128);
        int ret = -1;
        ret = read(p[0], buf, 128); //阻塞读,无数据,无进程关联写,立即返回
        printf("buf = %s
    ", buf);
    }

    第二、三种情况

    #include<stdio.h>
    #include<unistd.h>
    #include<string.h>
    #include<stdlib.h>
    
    int main(void)
    {
        int p[2];
        pipe(p);
        write(p[1], "helloworld", 10);  //写入10个字节
         close(p[1]);                     //断开当前进程与管道写端的联系
        char buf[128];
        memset(buf, '', 128);
        int ret = -1;
        ret = read(p[0], buf, 3); //有数据,且大于期望读出值
        printf("first, ret = %d, buf = %s
    ", ret, buf);
        ret = read(p[0], buf, 15); //有数据,且小于期望读出值
        printf("second, ret = %d, buf = %s
    ", ret, buf);
    }

    (2)以阻塞方式读取无名管道,且当前有进程可以访问写端

    • 管道中无任何数据,读操作阻塞
    • 管道中有数据,现有数据大小小于期望读出值,读出现有数据并返回。
    • 管道中有数据,现有数据大小大于期望读出值,读出期望大小的数据并返回。

    第一种情况

    int main(void)
    {
        int p[2];
        pipe(p);
        char buf[128];
        memset(buf, '', 128);
        int ret = -1;
        ret = read(p[0], buf, 128); //阻塞读,无数据,无进程关联写,立即返回
        printf("buf = %s
    ", buf);
    }

    阻塞了,通过Ctrl+C退出。

    第二、三种情况(其实跟之前的代码比就少了一句close)

    int main(void)
    {
        int p[2];
        pipe(p);
        write(p[1], "helloworld", 10);  //写入10个字节
        char buf[128];
        memset(buf, '', 128);
        int ret = -1;
        ret = read(p[0], buf, 3); //有数据,且大于期望读出值
        printf("first, ret = %d, buf = %s
    ", ret, buf);
        ret = read(p[0], buf, 15); //有数据,且小于期望读出值
        printf("second, ret = %d, buf = %s
    ", ret, buf);
    }

    (3)如果以阻塞方式写无名管道,如果当前没有可以访问读端的进程,写操作将收到SIGPIPE信号,write返回-1.

    #include<stdio.h>
    #include<string.h>
    #include<signal.h>
    
    void handler(int sig)
    {
        if(SIGPIPE == sig)
            printf("recv SIGPIPE
    ");
    }
    int main(void)
    {
        int p[2];
        signal(SIGPIPE, handler);
        pipe(p);
         close(p[0]);                     //断开当前进程与管道读端的联系
        int ret = -1;
        ret = write(p[1], "helloworld", 10);  //写入10个字节
        printf("ret = %d
    ", ret);
    }

    (4)如果以阻塞方式写无名管道,如果当前管道已经满,则阻塞当前进程。多个进程试图写管道需要避免竞争的机制。写入建议小于PIPE_BUF(默认4096)大小。

    (5)如果以O_NDELAY或O_NONBLOCK设置了管道的读端,如果管道中没有数据,将立即返回-1,且置errno为EAGAIN错误

    (6)如果以O_NDELAY或O_NONBLOCK设置了管道的写端,如果管道中没有足够空间,将立即返回-1,且置errno为EAGAIN错误

  • 相关阅读:
    用于表示socket的结构体
    Parcelable与Serializable接口的用法和区别
    java类初始化顺序
    孙卫琴java面向对象编程学习笔记
    linux档案权限
    js弹出模态与非模态页面
    ubuntu开启默认的root用户
    java开发实战学习笔记1
    JQuery ajax回调函数
    hadoop命令
  • 原文地址:https://www.cnblogs.com/dplearning/p/4680240.html
Copyright © 2011-2022 走看看