运行环境

  • win11 linux子系统Ubuntu2204
  • g++ 11.3.0

Linux DESKTOP-XXXXX 5.15.79.1-microsoft-standard-WSL2 #1 SMP Wed Nov 23 01:01:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

管道的概念

管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:

  1. 其本质是一个伪文件(实为内核缓冲区)

  2. 由两个文件描述符引用,一个表示读端,一个表示写端。

  3. 规定数据从管道的写端流入管道,从读端流出。

管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。

管道的局限性:

① 数据自己读不能自己写。

② 数据一旦被读走,便不在管道中存在,不可反复读取。

③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。

④ 只能在有公共祖先的进程间使用管道。

常见的通信方式有,单工通信、半双工通信、全双工通信。

pipe函数

创建管道:

  • int pipe(int pipefd[2]); 成功:0;失败:-1,设置errno

函数调用成功返回r/w两个文件描述符。无需open,但需手动close。规定:fd[0] → r; fd[1] → w,就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。

父子进程使用pipe通讯

简单示例:

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

int main(int argc, char const* argv[])
{
    int fd[2];
    if (pipe(fd) == -1) 
	{
        perror("管道创建失败");
    }
    
    pid_t pid = fork();
    if (pid > 0)
	 { 
		// 父进程,读端:fd[0]
        char buf[256];
        bzero(buf, 256);
        read(fd[0], buf, 256);
        printf("child say %s\n", buf);
        wait(NULL);
    }
    else if (pid == 0) 
	{
		// 子进程,写端:fd[1]
        char s[256] = { "hello father." };
        write(fd[1], s, strlen(s));
        exit(0);
    }
    else {
        printf("进程创建失败\n");
    }
    close(fd[0]);
    close(fd[1]);
    return 0;
}