Linux之进程间通信(一)

1. 什么是进程间通信

进程是操作系统隔离的独立程序,每个进程有自己独立虚拟地址空间。 默认情况下:A 进程不能直接读写 B 进程的内存,互相看不见对方的数据。

IPC:让多个进程之间交换数据、传递消息、同步协作的一套机制

2. 为什么需要 IPC?为什么要这么做

① 数据共享

一个进程产生数据,另一个进程要拿来用。 例子:

  • shell 执行管道命令 ls | grep txt ls进程输出结果,交给grep进程做过滤,两个进程必须传数据,没有 IPC 就做不到。

② 任务拆分,分工协作

把一件大任务拆成多个进程并行干活。 比如:父进程 fork 出子进程,子进程负责计算,父进程负责接收结果打印;子进程干活,父进程负责调度。 多个进程分工,就要互相传递结果。

③ 事件通知、状态同步

进程 A 告诉进程 B:"我做完了,你可以开始执行"。 实现进程之间的等待、通知。

④ 资源协调

多个进程抢同一个资源,通过 IPC 做互斥,防止乱抢出错。

如果没有 IPC:进程之间完全孤岛,fork 出来子进程复制一份内存,fork 之后父子进程修改各自变量互不影响,父子不能直接互通。

3.怎么做

进程间是有独立性的,

首先让不同的进程,要先看到同一份资源

该功能由OS提供

通信原理

参数

pipefd[2] 是输出型参数,传入一个 int 数组,pipe 函数会往里面填入两个文件描述符:

  • pipefd[0]读端 read end,从管道读取数据
  • pipefd[1]写端 write end,向管道写入数据

💡 管道是单向半双工 :数据只能从 pipefd[1] 写入,从pipefd[0]读出,不能反向。

cpp 复制代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/wait.h>
int main()
{
    //创建管道
    int pipefd[2]={0};
    int n=pipe(pipefd);
    if(n<0)
    {
        perror("pipe");
        return 1;
    }
    printf("pipefd[0]:%d,pipefd[1]:%d\n",pipefd[0],pipefd[1]);

    //创建子进程
    pid_t id=fork();
    if(id==0)
    {
        //子进程
        close(pipefd[0]);
        char msg[]="hello world\n";
        int cnt=10;
        char outbuffer[1024];
        while(cnt)
        {
            snprintf(outbuffer,sizeof(outbuffer),"f->c# %s %d %d\n",msg,cnt--,getpid());//snprintf->最后加\0
            write(pipefd[1],outbuffer,strlen(outbuffer));//要不要+1??
        }
        // write(pipefd[1],msg,strlen(msg));
        exit(0);
    }
    //父进程
    close(pipefd[1]);
    char inbuffer[1024];
    while (1)
    {
        size_t n=read(pipefd[0],inbuffer,sizeof(inbuffer)-1);//read不管什么都要读,我们最后\0
        if(n>0)
        {
            inbuffer[n]=0;//0->\0
            printf("%s\n",inbuffer);
        }
        else if(n==0)
        {

        }
        else
        {
            perror("read");
            break;
        }
    }
    
    pid_t rid=waitpid(id,NULL,0);
    (void)rid;
    return 0;
}

管道特性

1.管道只能单向通信,单工通信
2.匿名管道只能用来进行拥有血缘关系的进程之间通信,常用父子通信
3.管道是面向字节流的
4.管道生命周期随进程
5.管道通信,对于多进程而言,是自自带互斥与同步机制

管道通信前提是让不同进程看到同一份资源--文件--文件内的缓冲区--内存块,这是属于父子进程的共享资源,存在并发访问的问题----互斥与同步

互斥:保护共享资源,同一时刻,只允许一个进程访问临界资源。

临界资源:管道缓冲区、共享内存,一次只能一个人改,不能多人同时写。

同步:进程之间执行时序上的等待、通知,协调先后顺序。 简单说:A 进程要等 B 进程做完某件事,A 才继续干活。

管道天然自带同步机制(阻塞):

  1. 读端read():管道缓冲区为空,读进程阻塞休眠,等待别的进程往管道写数据。
  2. 写端write():管道缓冲区满,写进程阻塞休眠,等待别的进程把数据读走,腾出空间

4种情况

1.子进程写的慢,父进程要阻塞等待,扽管道有数据,父进程才能读
2.子进程写的快,父进程不读,管道一旦被写满,子进程就必须阻塞了

管道为空,读就要阻塞,给写机会;管道为满,写就要阻塞,给读机会。

让子进程一直向管道里面去写

让父进程一直等待

  • 子进程:循环不停向管道写字符'a'不关闭写端
  • 父进程:sleep(100)睡很久,才调用read读取管道

现象

  1. 管道缓冲区有空:write直接返回,子进程疯狂循环,size 持续上涨。
  2. 管道缓冲区写满之后write(pipefd[1])阻塞,子进程卡在 write 系统调用,不再 printf 打印 size。
  3. 父进程还在sleep(100),迟迟不调用 read;此时子进程被内核挂起,不再跑。
  4. 100 秒之后父进程 read,一次性把缓冲区的数据全部读出来,打印。
3.读端在读,写端关闭,读端读完管道中的数据,在读就会读到空串,read返回值为0,表明读管道读到文件结尾

子进程写完,然后关闭

父进程一直读

  • 子进程:write 写数据 → close(pipefd[1])(子进程写端关闭)
  • 父进程早已执行 close(pipefd[1])所有写端全部关闭
  • 第一次 read:读到管道缓冲区数据,n=13,inbuffer 被填充为hello world\n
  • 第二次及以后 read:管道空,全部写端已关闭 → read返回0。内核不会往 inbuffer 拷贝任何字节
4.写端一直在写,读端不读关闭 fd OS 会直接杀掉写的进程!!

子进程一直在往管道写

父进程读了一次后,不在读取管道

信号 13 = SIGPIPE,就是管道写的时候,所有读端已经关闭,内核发送管道破裂信号杀死子进程

一个进程控制一批进程

read的时候进程会阻塞等待

父进程

  • 循环创建 4 个子进程,每 fork 一次,创建一根 pipe。
  • 父进程保留每根管道的写端,关闭读端。
  • 每个子进程保留对应管道的读端,关闭写端。
  • 需要派发任务时:父进程选中某一根管道,写入 1 字节任务编号,对应子进程收到后运行任务。

这是 Linux 经典主从模式进程池,利用匿名管道完成父子进程任务分发。

Master‑Slave 进程池

  • Master(父进程,主) :负责任务调度,拥有 4 根管道的写端,向管道写入任务编号
  • Slave(子进程,从,共 4 个):每个子进程绑定一根管道的读端,阻塞等待读取任务号,拿到编号执行对应函数。
  • func_t tasks[4]:函数指针数组,存放 4 个任务函数,tasks[ch]就取出对应任务执行。
相关推荐
轻揉小乔 真新人1 小时前
T-SQL查询进阶—理解SQL Server中的锁
服务器·数据库·sql
各类产品分享1 小时前
电力行业AR智能运维哪个品牌好
运维·ar·ar巡检
Dlrb12111 小时前
Linux驱动---sys文件系统自动添加设备节点、添加调试节点以及MISC设备驱动的解释
linux·imx6ull·misc·设备节点·sys文件系统
贾天佑忆月 迷失的昵2 小时前
客户端与服务器持续同步解析(轮询,comet,WebSocket)
运维·服务器·websocket
刘某的Cloud2 小时前
Galera Cluster mariadb 生产环境常见问题排查与运维指南
linux·运维·数据库·mariadb·集群高可用
70asunflower2 小时前
Linux 性能排查分析完全教程
linux·运维
兵bing3 小时前
Docker Compose 配置文件归纳总结-千问
运维·docker·容器
dok123 小时前
Johannes 《Linux内核模块与设备驱动开发:编写Linux驱动程序》 (11)kmalloc 动态内存分配和struct file中的私有数据
linux·驱动开发·算法
IT小盘3 小时前
17-构建Prompt测试集-提示词优化不再凭感觉
服务器·windows·prompt
INNOVIX稳石机器人4 小时前
从“存得下”到“管得活”:稳石四向穿梭车如何重塑密集仓储新逻辑?
大数据·运维