管道(pipe)

本文详细探讨了Unix/Linux操作系统中的管道(Pipe)机制,它是一种简单的进程间通信方式,允许将一个进程的输出作为另一个进程的输入。通过管道,可以实现命令的连接,创建强大的命令链,提高shell脚本的效率。文中还讲解了管道的实现原理,包括内核缓冲区的使用以及读写进程间的同步和信号量机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

二、管道的本质:
    1、其本质是一个伪文件(实为内核缓冲区)。
    2、有两个文件描述符引用,一个表示读端,一个

表示写端。
    3、规定数据由管道的写端流入管道,由读端流出。

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

四、管道的局限:
    1、数据自己读但不能自己写。

    2、数据一旦被独奏,便不在管道中存在,不可反复读取。
    3、由于管道采用半双工通讯方式,因此数据只能在一个方向流动。

    4、只能在公共祖先的进程间使用管道。
    5、常用的通信方式有,单工通信,半双工通信,全双工通信。

五、pipe函数:
    1、创建管道:int pipe(int fd[2]);成功返回:0;失败返回-1,设置errno。函数调用成功返回r/w两个文件描述符。无需open,但需要手动的close。规定:fd[0]->r;fd[1]->w,就像0对应标准输入,1对应标准输出一样。向管道文件写数据其实是在读写内核缓冲区。

    练习:父子进程使用管道通信,父进程写入字符串,子进程读出字符串。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
void sys_err(const char *str)
{
        perror(str);
        exit(1);
}
int main()
{
        pid_t pid;
        char buf[1024];
        int fd[2];
        char *p = "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、如果所指向的管道写端的文件描述符都关闭了(管道写端引用计数为0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read返回0,就像读到文件末尾一样。
2、如果有指向管道写端的文件描述符没关闭(管道写端引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余数据都被读取后,再次read阻塞,直到管道中有数据可读了才读取数据并返回。

3、如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数为0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。当然也可以对SIGPIPE信号实施捕捉,不终止进程。
4、如果有指向管道读端的文件描述符没关闭(管道读端引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程相管道中写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置写入数据并返回。

七、练习一个读端,多个写端(父进程读数据,两个子进程写入数据)。
include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
        pid_t pid;
        int fd[2],i,n;
        char buf[1024];
        int ret = pipe(fd);
        if (ret == -1)
        {
                perror("pipe error");
                exit(1);
        }
        for (i = 0;i < 2;i++)
        {
                if ((pid = fork()) == 0)
                        break;
                else if (pid == -1)
                {
                        perror("fork error");
                         exit(1);
                }
        }
        if (i == 0)
        {
                close(fd[0]);
                write(fd[1],"1.hello\n",strlen("1.hello\n"));
        }
        else if(i == 1)
        {
                sleep(1);
                close(fd[0]);
                write(fd[1],"2.hello\n",strlen("2.hello\n"));
        }
        else
        {
                close(fd[1]);
                sleep(2);
                n = read(fd[0],buf,1024);
                write(STDOUT_FILENO,buf,n);
        }
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值