几种常见进程间通信(IPC)方式之管道pipe

几种常见进程间通信(IPC)方式-管道pipe

前言

进程间通信是指在不同进程之间传播或交换信息,在Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间,进程之间不能相互访问。必须通过内核才能进行数据交换。如图:
在这里插入图片描述
常见的通信方式有以下几种:

  • 管道pipe
  • 有名管道FIFO
  • 消息队列MessageQueue
  • 共享存储
  • 信号量Semaphore
  • 信号Signal
  • 套接字Socket

接下来我们将详细介绍管道

管道pipe

管道作用于有血缘关系的进程之间,调用pipe系统函数可以创建管道。

  • 原理:管道实为内核使用环形队列机制(以便管道可以重复利用),借助内核缓冲区(4k)实现
  • 本质:是一个伪文件(实为内核缓冲区),由两个文件描述符引用,一个表示读端,一个表示写端。数据从管道的写端流入,从读端流出。

管道具有一定的局限性

  • 一个进程只能控制读端或写端,不能同时自己写自己读。
  • 数据不可反复读取,一旦被读走,在管道中就不复存在了。
  • 管道采用 半双工通信方式,数据只能在一个方向上流动。
  • 只能作用于有亲缘关系的进程间通信
创建管道 pipe()
//成功返回0,失败返回-1
int pipe(int pipefd[2]);

函数调用成功会返回r/w两个文件描述符,规定pipefd[0]对应r,规定pipefd[1]对应w(需要手动close)。
父子间管道通信步骤如下:

  • 父进程调用pipe函数创建管道,得到两个文件描述符,分别指向管道的读端和写端。
  • 父进程调用fork创建子进程,那么子进程也会得到这两个文件描述符并且指向同一个管道。
  • 父进程关闭管道读端(或写端),子进程关闭管道写端(或读端)。

这样一来,父进程可以向(从)管道中写(读)数据,子进程可以读(写)数据。

在这里插入图片描述

例子:

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>

void sys_err(const char *str)
{
        perror(str);
        exit(1);
}

int main(void)
{
        pid_t pid;
        char buf[1024];
        int fd[2];
        char *p = "this is a test for pipe\n";
        //父进程创建管道
        if (pipe(fd) == -1)
                sys_err("pipe");
        //父进程创建子进程
        pid = fork();
        if (pid < 0) {
                sys_err("fork err");
        //子进程进入
        } else if (pid == 0) {
                //子进程关闭写端
                close(fd[1]);
                int len = read(fd[0], buf, sizeof(buf));
                //输出到终端
                write(STDOUT_FILENO, buf, len);
                //子进程关闭写端
                close(fd[0]);
        //父进程进入
        } else {
                //父进程关闭读端
                close(fd[0]);
                write(fd[1], p, strlen(p));
                wait(NULL);
                //父进程关闭读端
                close(fd[1]);
        }

        return 0;
}
管道的读写行为
  • 读管道
    1.管道中有数据,read返回实际读到的字节数。
    2.管道中无数据:
    (1)管道写端被全部关闭,read返回0
    (2)管道写端没有全部被关闭,read阻塞等待(等待管道中有数据可读)
  • 写管道
    1.管道读端全部被关闭,进程异常终止。
    2.管道读端没有全部关闭:
    (1)管道已满,write阻塞。
    (2)管道未满,write将数据写入,并返回实际写入的字节数。
管道缓冲区大小
//命令查看当前系统中创建管道文件所对应的内核缓冲区的大小
ulimit -a

pipe size

在这里插入图片描述

//成功:返回管道的大小,失败:返回-1
long fpathconf(int fd, int name);

总结

管道最大的优点就是简单,也有很多缺点,一个管道只能进行单向通信,想要实现双向通信必须建立两个管道。
并且只适用于有亲缘关系的进程间相互通信。接下来将要介绍有名管道FIFO,它解决了这个问题。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值