Linux:匿名管道的四种情况(进程间通信四)

了解了匿名管道的五种特性后,我们必须得谈谈匿名管道的四种情况--快读慢写,快写慢读,只写不读,只读不写,接下来我将一一讲述,话不多说现在开始

1.快读慢写

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdio>
#include <cstring>

void ChildWrite(int wfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        buffer[0] = '\0';
        snprintf(buffer, sizeof(buffer), "我是子进程, pid : %d, cnt : %d", getpid(), cnt++);
        write(wfd, buffer, strlen(buffer));
        sleep(1);
    }
}

void FutherRead(int rfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        buffer[0] = '\0';
        ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << buffer << std::endl;
        }
    }
}

int main()
{
    // 创建管道
    int pfd[2] = {0};
    int n = pipe(pfd);
    if (n == -1)
    {
        std::cerr << "pipe error!" << std::endl;
        return 1;
    }
    std::cout << "pfd[0] : " << pfd[0] << std::endl;
    std::cout << "pfd[1] : " << pfd[1] << std::endl;
    // 一般来说,pfd[0] -> 读端   pfd[1] -> 写端
    // 创建子进程
    pid_t id = fork();
    if (id == 0)
    {
        // 关闭子进程读端
        close(pfd[0]);

        // 子进程向管道写入内容
        ChildWrite(pfd[1]);

        // 关闭子进程写端
        close(pfd[1]);
    }
    // 关闭父进程写端
    close(pfd[1]);

    // 父进程读取管道内容
    FutherRead(pfd[0]);

    // 等待子进程结束
    waitpid(id, nullptr, 0);

    // 关闭父进程读端
    close(pfd[0]);
    return 0;
}

实验结果--读端阻塞,等待写端

2.快写慢读

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdio>
#include <cstring>

void ChildWrite(int wfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        buffer[0] = '\0';
        snprintf(buffer, sizeof(buffer), "我是子进程, pid : %d, cnt : %d", getpid(), cnt++);
        write(wfd, buffer, strlen(buffer));
        //sleep(1);
    }
}

void FutherRead(int rfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        sleep(5);
        buffer[0] = '\0';
        ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << buffer << std::endl;
        }
    }
}

int main()
{
    // 创建管道
    int pfd[2] = {0};
    int n = pipe(pfd);
    if (n == -1)
    {
        std::cerr << "pipe error!" << std::endl;
        return 1;
    }
    std::cout << "pfd[0] : " << pfd[0] << std::endl;
    std::cout << "pfd[1] : " << pfd[1] << std::endl;
    // 一般来说,pfd[0] -> 读端   pfd[1] -> 写端
    // 创建子进程
    pid_t id = fork();
    if (id == 0)
    {
        // 关闭子进程读端
        close(pfd[0]);

        // 子进程向管道写入内容
        ChildWrite(pfd[1]);

        // 关闭子进程写端
        close(pfd[1]);
    }
    // 关闭父进程写端
    close(pfd[1]);

    // 父进程读取管道内容
    FutherRead(pfd[0]);

    // 等待子进程结束
    waitpid(id, nullptr, 0);

    // 关闭父进程读端
    close(pfd[0]);
    return 0;
}

实验结果--写端阻塞,等待读端

3只写不读

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdio>
#include <cstring>

void ChildWrite(int wfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        buffer[0] = '\0';
        snprintf(buffer, sizeof(buffer), "我是子进程, pid : %d, cnt : %d", getpid(), cnt++);
        write(wfd, buffer, strlen(buffer));
        //sleep(1);
        //break;
    }
}

void FutherRead(int rfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        //sleep(5);
        buffer[0] = '\0';
        ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << buffer << std::endl;
        }
        /*
        else if (n == 0)
        {
            std::cout << "没有内容 : " << n << std::endl;
            std::cout << "子进程退出,我也退出" << n << std::endl;
            break;
        }
        else
        {
            break;
        }*/
       break;
    }
}

int main()
{
    // 创建管道
    int pfd[2] = {0};
    int n = pipe(pfd);
    if (n == -1)
    {
        std::cerr << "pipe error!" << std::endl;
        return 1;
    }
    std::cout << "pfd[0] : " << pfd[0] << std::endl;
    std::cout << "pfd[1] : " << pfd[1] << std::endl;
    // 一般来说,pfd[0] -> 读端   pfd[1] -> 写端
    // 创建子进程
    pid_t id = fork();
    if (id == 0)
    {
        // 关闭子进程读端
        close(pfd[0]);

        // 子进程向管道写入内容
        ChildWrite(pfd[1]);

        // 关闭子进程写端
        close(pfd[1]);
    }
    // 关闭父进程写端
    close(pfd[1]);

    // 父进程读取管道内容
    FutherRead(pfd[0]);

    //验证只写不读,提前关闭读端
    close(pfd[0]);

    // 等待子进程结束
    waitpid(id, nullptr, 0);

    // 关闭父进程读端
    close(pfd[0]);
    return 0;
}

OS始终想着怎么优化,所以如果只写不读,那么就没有任何意义,操作系统不会做这种没有意义的事情,会直接杀死进程,下面我们来验证一下

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdio>
#include <cstring>

void ChildWrite(int wfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        buffer[0] = '\0';
        snprintf(buffer, sizeof(buffer), "我是子进程, pid : %d, cnt : %d", getpid(), cnt++);
        write(wfd, buffer, strlen(buffer));
        //sleep(1);
        //break;
    }
}

void FutherRead(int rfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        //sleep(5);
        buffer[0] = '\0';
        ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << buffer << std::endl;
        }
        /*
        else if (n == 0)
        {
            std::cout << "没有内容 : " << n << std::endl;
            std::cout << "子进程退出,我也退出" << n << std::endl;
            break;
        }
        else
        {
            break;
        }*/
       break;
    }
}

int main()
{
    // 创建管道
    int pfd[2] = {0};
    int n = pipe(pfd);
    if (n == -1)
    {
        std::cerr << "pipe error!" << std::endl;
        return 1;
    }
    std::cout << "pfd[0] : " << pfd[0] << std::endl;
    std::cout << "pfd[1] : " << pfd[1] << std::endl;
    // 一般来说,pfd[0] -> 读端   pfd[1] -> 写端
    // 创建子进程
    pid_t id = fork();
    if (id == 0)
    {
        // 关闭子进程读端
        close(pfd[0]);

        // 子进程向管道写入内容
        ChildWrite(pfd[1]);

        // 关闭子进程写端
        close(pfd[1]);
    }
    // 关闭父进程写端
    close(pfd[1]);

    // 父进程读取管道内容
    FutherRead(pfd[0]);

    //验证只写不读,提前关闭读端
    close(pfd[0]);

    // 等待子进程结束
    //waitpid(id, nullptr, 0);
    int status = 0;
    waitpid(id, &status, 0);
    std::cout << "exit code : " << ((status >> 8) & 0xFF) << std::endl;
    std::cout << "exit signal : " << (status & 0x7F) << std::endl;

    // 关闭父进程读端
    close(pfd[0]);
    return 0;
}

此时退出码为0,表示无意义,退出信号为13,符合预期

4.只读不写

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdio>
#include <cstring>

void ChildWrite(int wfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        buffer[0] = '\0';
        snprintf(buffer, sizeof(buffer), "我是子进程, pid : %d, cnt : %d", getpid(), cnt++);
        write(wfd, buffer, strlen(buffer));
        sleep(1);
        break;
    }
}

void FutherRead(int rfd)
{
    char buffer[1024];
    int cnt = 0;
    while (true)
    {
        //sleep(5);
        buffer[0] = '\0';
        ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << buffer << std::endl;
        }
        else if (n == 0)
        {
            std::cout << "没有内容 : " << n << std::endl;
            std::cout << "子进程退出,我也退出" << n << std::endl;
            break;
        }
        else
        {
            break;
        }
    }
}

int main()
{
    // 创建管道
    int pfd[2] = {0};
    int n = pipe(pfd);
    if (n == -1)
    {
        std::cerr << "pipe error!" << std::endl;
        return 1;
    }
    std::cout << "pfd[0] : " << pfd[0] << std::endl;
    std::cout << "pfd[1] : " << pfd[1] << std::endl;
    // 一般来说,pfd[0] -> 读端   pfd[1] -> 写端
    // 创建子进程
    pid_t id = fork();
    if (id == 0)
    {
        // 关闭子进程读端
        close(pfd[0]);

        // 子进程向管道写入内容
        ChildWrite(pfd[1]);

        // 关闭子进程写端
        close(pfd[1]);
    }
    // 关闭父进程写端
    close(pfd[1]);

    // 父进程读取管道内容
    FutherRead(pfd[0]);

    // 等待子进程结束
    waitpid(id, nullptr, 0);

    // 关闭父进程读端
    close(pfd[0]);
    return 0;
}

只读不写场景是指读进程持续读取数据,但写进程停止写入且关闭了写端 ,此时读端会读取完管道中剩余数据,随后检测到 "文件结束(EOF)",read() 返回 0,读进程可正常退出

5.四种场景核心结论与特性总结

通过对四种场景的分析,我们可以归纳出匿名管道的三大核心特性,以及对应的场景体现:

匿名管道特性 对应场景 核心表现
自带同步机制 快读慢写、快写慢读 读端空则阻塞读进程,写端满则阻塞写进程
内核缓冲区有容量限制 快写慢读 写端写入速度过快时,缓冲区满后阻塞写进程
半双工 + 面向字节流 所有场景 数据单向传输,无消息边界,读端按字节读取
EOF 检测机制 只读不写 所有写端关闭后,读端 read() 返回 0
异常场景信号终止 只写不读 读端关闭后,写端收到 SIGPIPE 信号

好啦,这就是有关匿名管道通信的四种情况啦,希望大家可以多多看哦~~

相关推荐
暗影凋落2 分钟前
docker-image 工具展示更详细镜像层内容
运维·docker·容器
深圳市爱派派智能科技有限公司15 分钟前
“进迭时空 RISC-V 集群服务器 CSB1-N10SPK3:10 节点 K3,600 TOPS 绿色算力“
运维·服务器·risc-v·k3·进迭时空·集群服务器
☆凡尘清心☆15 分钟前
Linux运维故障排查速查命令清单
linux·运维·服务器
QWEDDRFTG18 分钟前
机房供电安全
服务器
极客先躯20 分钟前
高级java每日一道面试题-2026年05月11日-实战篇[Docker]-如何容器化金融产品推荐系统?
java·运维·docker·容器·金融·高级面试·金融产品推荐系统
小泊客21 分钟前
友善R5C刷OpenWrt后RTL8822CE无线网卡显示“禁用”或“未激活”的完整解决方案
linux·github·运维开发
nvd1123 分钟前
GCP L4 Passthrough 负载均衡器“假死超时”深度排查复盘
运维·php·负载均衡
mounter62524 分钟前
跨内核实时更新:如何实现 hugetlbfs 巨页的无缝保留与恢复?
linux·linux kernel·kernel·kexec·liveupdate·kho
qeen8733 分钟前
【Linux】make/Makefile 自动化工具的介绍
linux·运维·服务器·自动化
朱容zr33313336 分钟前
为什么推荐使用自增主键?使用UUID作为主键的优缺点是什么?
java·运维·数据库·后端·mysql·面试·性能优化