【Linux】进程间通信之匿名管道

文章目录

进程间通信背景

键盘,显示器只有一份,不同进程要想通信前提是不同进程看到同一份资源,键盘和显示器是文件,管道也是文件


两个进程都能控制相同的文件,(之前文件描述符讲过了,这里有计数器)

管道

管道定义

  • 管道是UnIx最古老的通信方式
  • 把一个进程连接到另一个进程的数据流叫做管道

🚩匿名管道

建立通信很困难,因为进程有独立性

如何创建一个管道?

我们在一个进程中创建一个文件,该进程可以对文件读写,如果再来一个进程可以对该文件读写那就可以通信了。

哪来的另一个进程呢,用fork创建

此外,管道之所以叫管道,因为它是单向流通的,传送字节流,就像水龙头那般

我们会让一个进程只读取,一个进程只写入

按照上述文字表述,只要创建文件就可以通信,但是文件是建在硬盘上的,我们在硬盘上读写太慢了,关闭进程时文件也不会删除,所以有管道接口,建立在内存上,关闭进程时自动清理

接口

该函数会把文件描述符带出来,如果不手动打开任何文件,
pipefd[0]:3
pipefd[1]:4

若打开文件,则文件描述符继续排

其中默认pipefd[0],读文件
pipefd[1],写文件

🚩实现匿名管道

c 复制代码
int main()
{
    int pipefd[2]={0};
    int n=pipe(pipefd);
    if(n<0)
    {
        return 1;
    }
    cout<<"pipe[0]:"<<pipefd[0]<<"pipe[1]:"<<pipefd[1]<<endl;
    
    int id=fork();
    if(id<0)
    {
        cout<<"fork error"<<endl;
    }
    if(id==0)
    {
        close(pipefd[0]);
        Writer(pipefd[1]);
        close(pipefd[1]);
        exit(0);
    }

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

    sleep(5);
    int pid=waitpid(id,nullptr,0);
	if(pid<0)
    {
        cout<<"waitpid error"<<endl;
        return 3;
    }
    return 0;
}

🚩解析,先让pipe创建内存级缓冲区,fork创建子进程,如果是子进程,关闭读端,把写端给函数写入,
如果是父进程,关闭写端,把读端给函数,
进行通信,通信结束后,子进程退出,父进程回收子进程

写和读函数实现

c 复制代码
void Writer(int wrd)
{
    string s="hello pipe";
    pid_t self=getpid();
    char buffer[1024];

    int number=0;
    while(true)
    {

        buffer[0]=0;
        snprintf(buffer,sizeof(buffer),"%s-%d-%d",s.c_str(),self,number);
        cout<<buffer<<endl;
        number++;
        write(wrd,buffer,strlen(buffer));
        if(number>5)
        break;

        sleep(1);
    }

}
void Reader(int rrd)
{
    char buffer[1024]={0};
    while(true)
    {
        buffer[0]=0;
        int n=read(rrd,buffer,sizeof(buffer));
        if(n>0)
        {
            buffer[n]=0;
            cout<<"father get message"<<"["<<getpid()<<"]#:"<<buffer<<endl;
        }
        else if(n==0)
        {
            cout<<"read file done"<<endl;
            break;
        }
        else
        break;
    }
}

解析:写入函数,buffer置空,把数据打印到buffer,向wrd中写入buffer,每隔1秒写一次,写6次后退出,
读取函数,一直在读取,把数据读取到buffer中,再打印出buffer,若没数据可读,read返回0

结果就是

🚩管道属性和特征

管道是有大小的,怎么测?
我们把读端关闭,疯狂的向管道1字节1字节写入,打印即可

c 复制代码
int number=0;
    while(true)
    {
        number++;
        char ch='c';
        write(wrd,&ch,1);
        cout<<number<<endl;
    }
}

读端sleep100秒

65536/1024=64kb

⭐所以1个管道大小64字节,

⭐原子写入最大字节数4kb,即小于4kb的数据可以直接写入(更大数据需要分片),保证全部写入成功否则失败

🚩保证了不会与其他写入交叉冲突,

比如A进程写入AAAA,B进程写入BBBB,若没有原子写入,可能会写进去AAABBBAB,而有原子写入AAAABBBB或BBBBAAAA

⭐管道5大特征

1,匿名管道是具有血缘关系的进程通信

2,管道是单向通信

3,父子进程是会协同的,同步与互斥,保证了数据安全,

4,管道面向字节流

5,管道基于文件描述符可以像操作文件一样操作管道,但管道不是磁盘文件,操作系统开辟了一块内核缓存区给管道用,而内核缓存区生命周期随进程

⭐管道4种情况

1,读写端正常,管道为空,则读端就要阻塞

2,读写端正常,管道满了,则写端就要阻塞

3,读端正常,写端关闭,则读端读到0,说明读到文件末尾,不会阻塞

4,写端正常,读端关闭,说明出bug,操作就要通过信号杀死写端进程

管道应用

我们之前学的ps axj | head -1
| 就是管道,意思是,左边写入 右边读取

可以看到3个进程父进程都是一样的,是具有血缘关系的

相关推荐
C++ 老炮儿的技术栈2 分钟前
GCC编译时无法向/tmp 目录写入临时汇编文件,因为设备空间不足,解决
linux·运维·开发语言·汇编·c++·git·qt
橘颂TA10 分钟前
【笔试】算法的暴力美学——牛客 NC213140 :除2!
c++·算法·结构与算法
Agent产品评测局14 分钟前
企业数据处理自动化落地,抓取分析全流程实现方案 —— 2026企业级智能体选型与技术路径深度解析
运维·人工智能·ai·自动化
autumn200516 分钟前
Flutter 框架跨平台鸿蒙开发 - 历史人物对话
服务器·flutter·华为·harmonyos
汀、人工智能34 分钟前
[特殊字符] 第66课:跳跃游戏
数据结构·算法·数据库架构·图论·bfs·跳跃游戏
爱莉希雅&&&38 分钟前
linux中MySQL数据库备份恢复的四种方法(更新中)
linux·数据库·mysql·数据库备份·mysqldumper
汀、人工智能43 分钟前
[特殊字符] 第70课:加油站
数据结构·算法·数据库架构·图论·bfs·加油站
wsoz1 小时前
Leetcode普通数组-day5、6
c++·算法·leetcode·数组
我科绝伦(Huanhuan Zhou)1 小时前
分享一个网络智能运维系统
运维·网络
鬼先生_sir1 小时前
Spring Cloud 微服务监控实战:SkyWalking + Prometheus+Grafana 全栈解决方案
运维·spring cloud·grafana·prometheus·skywalking