7.1.1 Linux管道的实现机制

在Linux中,管道是一种使用非常频繁的通信机制。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:

·      限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为1页,即4K字节,使得它的大小不象文件那样不加检验地增长。使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。

·      读取进程也可能工作得比写进程快。当所有当前进程数据已被读取时,管道变空。当这种情况发生时,一个随后的read()调用将默认地被阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。

注意:从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛弃,释放空间以便写更多的数据。

1. 管道的结构

在 Linux 中,管道的实现并没有使用专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。通过将两个 file 结构指向同一个临时的 VFS 索引节点,而这个 VFS 索引节点又指向一个物理页面而实现的。如图 7.1所示。

图7.1  管道结构示意图

图7.1中有两个 file 数据结构,但它们定义文件操作例程地址是不同的,其中一个是向管道中写入数据的例程地址,而另一个是从管道中读出数据的例程地址。这样,用户程序的系统调用仍然是通常的文件操作,而内核却利用这种抽象机制实现了管道这一特殊操作。

2.管道的读写

管道实现的源代码在fs/pipe.c中,在pipe.c中有很多函数,其中有两个函数比较重要,即管道读函数pipe_read()和管道写函数pipe_wrtie()。管道写函数通过将字节复制到 VFS 索引节点指向的物理内存而写入数据,而管道读函数则通过复制物理内存中的字节而读出数据。当然,内核必须利用一定的机制同步对管道的访问,为此,内核使用了锁、等待队列和信号。

当写进程向管道中写入时,它利用标准的库函数write(),系统根据库函数传递的文件描述符,可找到该文件的 file 结构。file 结构中指定了用来进行写操作的函数(即写入函数)地址,于是,内核调用该函数完成写操作。写入函数在向内存中写入数据之前,必须首先检查 VFS 索引节点中的信息,同时满足如下条件时,才能进行实际的内存复制工作:

·内存中有足够的空间可容纳所有要写入的数据;

·内存没有被读程序锁定。

如果同时满足上述条件,写入函数首先锁定内存,然后从写进程的地址空间中复制数据到内存。否则,写入进程就休眠在 VFS 索引节点的等待队列中,接下来,内核将调用调度程序,而调度程序会选择其他进程运行。写入进程实际处于可中断的等待状态,当内存中有足够的空间可以容纳写入数据,或内存被解锁时,读取进程会唤醒写入进程,这时,写入进程将接收到信号。当数据写入内存之后,内存被解锁,而所有休眠在索引节点的读取进程会被唤醒。

管道的读取过程和写入过程类似。但是,进程可以在没有数据或内存被锁定时立即返回错误信息,而不是阻塞该进程,这依赖于文件或管道的打开模式。反之,进程可以休眠在索引节点的等待队列中等待写入进程写入数据。当所有的进程完成了管道操作之后,管道的索引节点被丢弃,而共享数据页也被释放。

因为管道的实现涉及很多文件的操作,因此,当读者学完有关文件系统的内容后来读pipe.c中的代码,你会觉得并不难理解。

测试:【环境:Linux hgc-VirtualBox 3.5.0-26-generic #42~precise1-Ubuntu SMP Mon Mar 11 22:19:42 UTC 2013 i686 i686 i386 GNU/Linux】

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
    int pipefds[2]; //[0] for read, [1] for write
    pipe(pipefds);
    
    char buf[4096];
    for (int i = 0; i < sizeof(buf); ++i)
    {
        buf[i] = 0x7f;
    }
    
    ssize_t ret = -1;
    
    int loop = 100;
    if (argc > 1)
    {
        loop = atoi(argv[1]);
    }
    
    for (int i = 0; i < loop; ++i)
    {
        printf("loop: %d\n", i);
        ret = write(pipefds[1], buf, sizeof(buf));
        if (ret < 0)
        {
            perror(NULL);
        }
        else
        {
            printf("%d\n", ret);
        }
    } // 当i=16的时候会阻塞,可知管道大小为64k
    
    close(pipefds[0]);
    close(pipefds[1]);
    
    return 0;
}

获取Linux 内存页(基页)大小的命令:getconf PAGE_SIZE ,一般的输出是4096,即 4KB。

(转)Linux下管道的原理相关推荐

  1. 【流媒体服务器Mediasoup】 NodeJs与C++信令通信详解及Linux下管道通信的详解(五)

    目录 前言 匿名管道进程间通信 进程间管道 的创建与图解 MediaSoup中的管道创建 MediaSoup Channel的创建 NodeJs和 C++ 管道通信的过程 MediaSoup 消息确认 ...

  2. Linux脚本保存管道中的变量,Linux下管道重定向使用以及Shell编程(操作系统)

    实验名称:Linux的基本操作 实验目的: 1.了解管道和重定向 2.熟悉基本的Linux脚本的编写 实验环境:Ubuntu 12.4(32位,简体中文) 实验内容: 1.将当前用户目录下的文件清单输 ...

  3. Linux 下 TC 命令原理及详解<一>

    文章目录 1 前言 2 相关概念 3 使用TC 4 创建HTB队列 5 为根队列创建相应的类别 6 为各个类别设置过滤器 7 复杂的实例 Linux 下 TC 命令原理及详解<一> Lin ...

  4. linux下软件如何防破裂,linux下管道破裂的處理

    管道破裂的原因解釋如下 拷貝黏貼 我寫了一個服務器程序,在Linux下測試,然后用C++寫了客戶端用千萬級別數量的短鏈接進行壓力測試. 但是服務器總是莫名退出,沒有core文件. 最后問題確定為, 對 ...

  5. Linux 下 TC 命令原理及详解

    众所周知,在互联网诞生之初都是各个高校和科研机构相互通讯,并没有网络流量控制方面的考虑和设计,IP协议的原则是尽可能好地为所有数据流服务,不同的数据流之间是平等的.然而多年的实践表明,这种原则并不是最 ...

  6. qt char*转int_Qt在Linux下绘制文字原理-使用FreeType来绘制字形

    原文链接 Qt源码那些事儿-Qt绘制文字原理_使用FreeType来绘制字形​www.cryfeifei.cn 前言 Qt在Linux绘制字体是使用的FreeType. FreeType是一个用C语言 ...

  7. Linux命令管道工作原理与使用方法

    一.管道定义 管道是一种两个进程间进行单向通信的机制.因为管道传递数据的单向性,管道又称为半双工管道.管道的这一特点决定了器使用的局限性.管道是Linux支持的最初Unix IPC形式之一,具有以下特 ...

  8. linux下防火墙iptables原理及使用

    iptables简介 netfilter/iptables(简称为iptables)组成Linux平台下的包过滤防火墙,与大多数的Linux软件一样,这个包过滤防火墙是免费的,它可以代替昂贵的商业防火 ...

  9. linux下图片加密原理,Linux中常见的加密技术介绍

    常见的加密技术: 对称加密:非对称加密:单向加密:SSL/TLS:秘钥交换 1.对称加密 采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密 ...

最新文章

  1. linux线程怎样实时性,高效轻型线程怎么提高Linux实时性能?
  2. python必背100代码-这 100 道 Python 题,拿去刷!!!
  3. php 流媒体源码,BeMusic v2.3.6 – 音乐流媒体分享平台PHP源码
  4. 2022速卖通328大促活动招商规则出炉啦,热销高潜产品抢先看
  5. java加密方式有哪些_面完平安JAVA,他们说了这些
  6. 手把手带你领略双十一背后的核心组件Sentinel之流控规则
  7. 不重启的情况下linux系统安装中文包生效
  8. java实现登陆面试题_【Javaweb】笔面试题 ---(1)(示例代码)
  9. python matplotlib:figure,add_subplot,subplot,subplots讲解实现
  10. 懒惰的JSF Primefaces数据表分页–第1部分
  11. 技术解析:一文看懂 Anolis OS 国密生态 | 龙蜥专场
  12. 捋一捋20201217
  13. 基于中间人攻击给电视盒子安装apk
  14. dx12 龙书第五章学习笔记 -- 渲染流水线
  15. 汉庭董事长季琦:成功创业者的必经之路
  16. mysql 分区表如何恢复_如何恢复mysql 单个innodb 分区表
  17. 三菱FX5U系列PLC电池安装方法以及GX Works3内相关参数设置
  18. Storm Control 风暴控制
  19. 自贡方言词典241条
  20. machine learning 四要素

热门文章

  1. wheel安装+使用wheel安装第三方库+临时换源安装和永久换源安装
  2. 机器人局部避障的动态窗口法(dynamic window approach) DWA
  3. Linux dirname命令
  4. 0-1背包问题和背包问题
  5. python输出随机字符串代码
  6. hide,hidden,display:none,visibility的区别
  7. 个人能用的短信平台有哪些?看这一篇就够了
  8. Nodejs 开发最佳实践
  9. 国内NLP的那些人那些会
  10. 个人作业--四则运算3