Linux下进程间通信方式——pipe(管道)

Linux下进程间通信方式——pipe(管道)
参考自:https://www.cnblogs.com/wuyepeng/p/9747557.html
每个进程有 不同的用户地址空间,任何一个进程的全局变量在另一个进程中是不可见的
所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷贝到内核缓冲区,进程B在从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。
在这里插入图片描述
不同进程间通信本质:进程之间可以看到一份公共资源;而提供这份资源的形式或者提供者不同,造成了通信方式不同,而pipe就是提供这份公共资源的形式的一种。

1. 匿名管道

管道是由pip函数来创建的:
#include <unistd.h>
int pipe (int fd[2]);
//返回:成功返回0,出错返回-1

1.1管道如何实现进程间的通信

(1)父进程创建管道,得到两个描述符指向管道的两端
(2)父进程fork出子进程,子进程也有两个文件描述符指向同一个管道
(3)父进程关闭fd[0], 子进程关闭fd[1], 即父进程关闭管道读端,子进程关闭管道写端(因为管道只支持单向通信)。父进程可以往管道中写,子进程可以从管道中读,管道是由环形队列实现的,数据从写端流入从读端流出,这样就实现了进程间通信。

在这里插入图片描述

1.2如何用代码实现管道通信

#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main()
{
    int fd[2];
    int ret = pipe(fd);
    if(ret == -1)
    {
        perror("pipe error\n");
        return -1;
    }
    pid_t id = fork();
    if(id == 0)
    {
        int i = 0;
        close(fd[0]);
        char* child = "I am child!";
        while(i < 5)
        {
            write(fd[1], child, strlen(child) + 1);
            sleep(2);
            i++;
        }
    }
    else if(id > 0)
    {
        close(fd[1]);
        char msg[100];
        int j = 0;
        while(j < 5)
        {
            memset(msg, '\0', sizeof(msg));
            ssize_t s = read(fd[0], msg, sizeof(msg));
            cout << msg << endl;
            j++;
        }
    }
    else
    {
        perror("fork error\n");
        return -1;
    }
    return 0;
}

在这里插入图片描述

1.3 管道读取数据的四种的情况

(1)读端不读(fd[0]未关闭),写端一直写
在这里插入图片描述
(2)写端不写(fd[1]未关闭),但是读端一直读
在这里插入图片描述
(3)读端一直读,且fd[0]保持打开,而写端写了一部分数据不写了,并且关闭fd[1]。

在这里插入图片描述
如果一个管道读端一直在读数据,而管道写端的引⽤计数⼤于0决定管道是否会堵塞,引用计数大于0,只读不写会导致管道堵塞。

(4)读端读了一部分数据,不读了且关闭fd[0],写端一直在写且f[1]还保持打开状态。

在这里插入图片描述

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
    int fd[2];
    int ret = pipe(fd);
    if(ret == -1)
    {
        perror("pipe error\n");
        return -1;
    }
    pid_t id = fork();
    if(id == 0)
    {
        int i = 0;
        close(fd[0]);
        const char *child = "I am child!";
        while(i < 10)
        {
            write(fd[1], child, strlen(child) + 1);
            sleep(2);
            i++;
        }
    }
    else if(id > 0)
    {
        close(fd[1]);
        char msg[100];
        int status = 0;
        int j = 0;
        while(j < 5)
        {
            memset(msg, '\0', sizeof(msg));
            ssize_t s = read(fd[0], msg, sizeof(msg));
            printf("%s %d\n",msg,j);
            j++;
        }
        //写方还在继续,而读方已经关闭它的读端 
        close(fd[0]);
        pid_t ret = waitpid(id, &status, 0);
        printf("exitsingle(%d),exit(%d),   %d\n", status&0xff, (status >> 8) & 0xff, status);
       //status解释:
       //高八位存放该子进程退出时是否收到信号 
        //此低八位子进程正常退出时,退出码是多少
    }
    else
    {
        perror("fork error\n");
        return -1;
    }
    return 0;
}

在这里插入图片描述

使用kill -l 查看13号信号,可以知道13号信号代表SIGPIPE。

总结:
如果一个管道的写端一直在写,而读端的引⽤计数是否⼤于0决定管道是否会堵塞,引用计数大于0,只写不读再次调用write会导致管道堵塞;
如果一个管道的读端一直在读,而写端的引⽤计数是否⼤于0决定管道是否会堵塞,引用计数大于0,只读不写再次调用read会导致管道堵塞;
而当他们的引用计数等于0时,只写不读会导致写端的进程收到一个SIGPIPE信号,导致进程终止,只写不读会导致read返回0,就像读到件末尾样。

1.4管道的特点

1.管道只允许具有亲缘关系的进程之间相互通信,例如父子进程之间的通信。
2.管道只允许单向通信。
3.管道内部保证同步机制,从而保证访问数据的一致性
4.面向字节流
5.管道随进程存在,进程在管道在,进程消失管道对应的端口也关闭。

1.5管道的容量
测试管道容量大小只需要将写端一直写,读端不读且不关闭fd[0],即可。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
    int fd[2];
    int ret = pipe(fd);
    if (ret == -1)
    {
        perror("pipe error\n");
        return -1;
    }
    pid_t id = fork();
    if (id == 0)
    {   //child
        int i = 0;
        close(fd[0]);
        char *child = "I am  child!";
        while (++i)
        {
            printf("pipe capacity: %d\n", i*(strlen(child) + 1));
            //printf要写在write前面否则会因为write写满了而阻塞就不会进行下面的代码了,会使得输出计算少一次
            write(fd[1], child, strlen(child) + 1);
            
        }
        close(fd[1]);
    }
    else if (id>0)
    {   //father
        close(fd[1]);           //父进程的读端不能关闭,如果关闭了子进程写端会因为异常而退出
        waitpid(id, NULL, 0);
    }
    else
    {   //error
        perror("fork error\n");
        return -1;
    }
    return  0;
}   

在这里插入图片描述
可以看到写到65520之后管道堵塞了,而65536即为64K大小即为管道的容量

原理是:我们写端每次写入的数据大小是13,统计我们可以进行多少次写入,写入次数*13就是管道容量,因为65533+13=65546>65536所以就不能继续输入了,有因为内存对齐问题,所以我们可以知道容量一定是64k

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值