【Linux之进程间通信】02.无名管道

 
【Linux之进程间通信】

项目代码获取:https://gitee.com/chenshao777/linux-processes.git
(麻烦点个免费的Star哦,您的Star就是我的写作动力!)

02.无名管道

无名管道常用于有亲缘关系的进程通信,即父子进程之间的通信

int pipe(int pipefd[2]);

需要包含头文件

#include <unistd.h>

数组pipefd用于返回两个引用管道末端的文件描述符
pipefd[0]指的是管道的读取端
pipefd[1]指的是管道的写入端
创建成功返回0,失败返回-1

使用实例1(创建无名管道):
Linux进程会默认打开三个文件描述符:
0 :标准输入 stdin
1 :标准输出 stdout
2 :标准错误 stderror
所以 读取端操作符 = 3, 写入端操作符= 4

#include <unistd.h>
#include <stdio.h>

/*
    创建无名管道,默认写管道描述符为pipefd[1]=4,管道描述符为pipefd[0]=3
    创建成功返回0,失败返回-1
    无名管道只能实现亲缘关系进程间的通信
    测试命令: ./1.out
*/
int main(int argc, char *argv[])
{
    int pipefd[2];
    int pipe_res;

    /*创建无名管道*/
    pipe_res = pipe(pipefd);
    if(pipe_res == 0)
        /*
        Linux进程会默认打开三个文件描述符:
            0 :标准输入 stdin
            1 :标准输出 stdout
            2 :标准错误 stderror
        所以pipefd[0] = 3, pipefd[1] = 4
        */
        printf("pipefd[0] = %d, pipefd[1] = %d\n",pipefd[0],pipefd[1]);
    else
        printf("创建无名管道失败!\n");

    close(pipefd[0]);
    close(pipefd[1]);

    return 0;
}

使用实例2(无名管道读写操作):
读写无名管道(无名管道实际上是存在与内核空间的一个队列)
读管道是出队操作,写管道是入队操作
无名管道读数据后数据会被删除,如果没有读到数据则会堵塞
写管道写溢出后也会阻塞,写满是65536字节
测试命令: ./2.out

  1. 去掉 “/再次读管道,会阻塞/” 下面三行注释的运行结果:
    第一次读管道成功,接着阻塞(因为读管道后会数据被删除,管道空了再读会阻塞)
  2. 不去掉注释的运行结果:
    “没有写满1” 不会打印,因为无名管道写满是65536字节,代码中写了65537个字节,溢出了,所以会阻塞
#include <unistd.h>
#include <stdio.h>
#include <string.h>

/*
    读写无名管道(无名管道实际上是存在与内核空间的一个队列)
    读管道是出队操作,写管道是入队操作
    无名管道读数据后数据会被删除,如果没有读到数据则会堵塞
    写管道写溢出后也会阻塞,写满是65536字节
    测试命令: ./2.out
    结果: 第一次读管道成功,接着阻塞
*/
int main(int argc, char *argv[])
{
    int pipefd[2];
    int pipe_res;
    char write_buff[100] = "123451234512345";  //15个字节
    char read_buff[100] = {0};

    /*创建无名管道*/
    pipe_res = pipe(pipefd);
    if(pipe_res == 0)
        /*
        Linux进程会默认打开三个文件描述符:
            0 :标准输入 stdin
            1 :标准输出 stdout
            2 :标准错误 stderror
        所以pipefd[0] = 3, pipefd[1] = 4
        */
        printf("pipefd[0] = %d, pipefd[1] = %d\n",pipefd[0],pipefd[1]);
    else{
        printf("创建无名管道失败!\n");
        return -1;
    }

    /*写管道*/
    write(pipefd[1], write_buff, strlen(write_buff));

    /*读管道*/
    read(pipefd[0], read_buff, 100);
    printf("读管道数据1 = %s\n", read_buff);

    /*再次读管道,会阻塞*/
    // memset(read_buff, 0 ,sizeof(read_buff));
    // read(pipefd[0], read_buff, 100);
    // printf("读管道数据2 = %s\n", read_buff);

    char data = 1;
    for(long int i = 0; i < 65537; i++){
        write(pipefd[1], &data, 1);
    }

    printf("没有写满1\n");

    close(pipefd[0]);
    close(pipefd[1]);

    return 0;
}

使用实例3(主进程先运行,子进程后运行):

核心就是子进程读无名管道,父进程写无名管道
子进程读出数据判断后才能运行,没读到数据则一直阻塞,直到父进程写管道

#include <unistd.h>
#include <stdio.h>
#include <string.h>

/*
    通过无名管道使父进程先运行,子进程后运行
    测试命令: ./3.out
    结果: 第一次读管道成功,接着阻塞
*/
int main(int argc, char *argv[])
{
    int pipefd[2];
    int pipe_res;
    char pipe_value;

    /*创建无名管道*/
    pipe_res = pipe(pipefd);
    if(pipe_res == 0)
        printf("pipefd[0] = %d, pipefd[1] = %d\n",pipefd[0],pipefd[1]);
    else{
        printf("创建无名管道失败!\n");
        return -1;
    }

    /*创建进程*/
    pid_t pid_f;
    pid_f = fork();
    if(pid_f > 0)
    {
        while(1)
        {
            printf("我是父进程,睡眠2秒\n");
            sleep(2);
            printf("我是父进程\n");
            printf("我是父进程\n");
            printf("我是父进程\n");
            /*写无名管道*/
            pipe_res = 1;
            write(pipefd[1], &pipe_res, 1);
            sleep(1);
        }
    }else{
        while(1)
        {
            /*读无名管道*/
            read(pipefd[0], &pipe_res, 1);
            if(pipe_res == 1){
                printf("我是子进程\n");
                printf("我是子进程\n");
                printf("我是子进程\n");
                usleep(100000);
            }
        }
    }

    close(pipefd[0]);
    close(pipefd[1]);

    return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值