当前位置:首页>编程日记>正文

进程间通信(三)


管道调用

我们已经了解了高层的popen函数,现在我们继续来了解低层的pipe函数。这个函数提供了一个在两个函数之间传递数据的方法,而不必调用shell来解释所请求的命令的。同时他也为我们提供了更多的数据读写控制。

pipe函数的原型如下:

#include <unistd.h>
int pipe(int file_descriptor[2]);

pipe函数接受一个两个整数文件描述符的数组作为参数。他会使用两个新的文件描述符来填充这个数据并且返回一个零值。如果失败则会返回-1并且设置errno来指明失败原因。Linux手册页中所定义的错误如下:

EMFILE:进程正在使用的文件描述符过多
ENFILE:系统文件表已满
EFAULT:文件描述符不可用

返回的两个文件描述符以一个特殊的方式相连接。任何写入file_descriptor[1]的数据可以由file_descriptor[0]中读取。数据以先进先出的方式进行处理,通常简记为FIFO。这就意味着如果我们向file_descriptor[1]中写入字节1,2,3,那么由file_descriptor[0]中的读取就会产生1,2,3。这与堆栈不同,后者以后进先出的方式进行操作,通常简记为LIFO。

注意:在这里我们要清楚,这些是文件描述符,而不是文件流,所以我们必须使用低层的read与write调用来访问数据,而不是fread与fwrite。

下面的程序,pipe1.c,使用pipe来创建一个管道。

试验--pipe函数

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

int main()
{
    int data_processed;
    int file_pipes[2];
    const char some_data[] = "123";
    char buffer[BUFSIZ +1];

    memset(buffer,'/0',sizeof(buffer));

    if(pipe(file_pipes) == 0)
    {
        data_processed = write(file_pipes[1],some_data,strlen(some_data));
        printf("Wrote %d bytes/n",data_processed);
        data_processed = read(file_pipes[0],buffer,BUFSIZ);
        printf("Read %d bytes: %s/n",data_processed,buffer);
        exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
}

当我们运行这个程序,我们会得到下面的输出:

$ ./pipe1
Wrote 3 bytes
Read 3 bytes: 123

工作原理

这个程序使用两个文件描述符file_pipes[]来创建一个管道。然后他使用文件描述符file_pipes[1]向管道中写入数据,并且由file_pipes[0]中读取。注意管道有内部缓冲,从而可以在两个调用write与read之间存储数据。

我们应该清楚尝试使用file_pipes[0]写入数据,或是使用file_pipes[1]读取数据的效果是未定义的,所以这样的行为结果会非常奇怪,并且也许会毫无警告的发生改变。在作者的系统上,这样的调用会失败并且返回-1,这至少保证了是很容易捕获这个错误的。

粗看起来这个管道的例子似乎并没有为我们提供任何我们使用一个简单的文件不能完成的任务。管道的真正优点在我们希望在两个进程之间传递数据时才会体现出来。正如我们在第12章所看到的,当一个程序使用fork调用创建一个新进程时,以前打开的文件描述符会保持打开。通过在原始进程中创建一个管道,然后通过fork创建一个新进程,我们可以由一个进程向另一个进程传递数据。

试验--使用fork的管道

1 这是pipe2.c。这个程序的开始部分与第一个例子类似,直到我们调用fork。

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

int main()
{
    int data_processed;
    int file_pipes[2];
    const char some_data[] = "123";
    char buffer[BUFSIZ + 1];
    pid_t fork_result;

    memset(buffer,'/0',sizeof(buffer));

    if(pipe(file_pipes)==0)
    {
        fork_result = fork();
            if(fork_result == -1)
            {
                fprintf(stderr,"Fork failure");
                exit(EXIT_FAILURE);
            }

2 我们已经保证fork正常工作,所以如果fork_result等于0,我们是在子进程中:

            if(fork_result == 0)
            {
                data_processed = read(file_pipes[0],buffer,BUFSIZ);
                printf("Read %d bytes: %s/n",data_processed,buffer);
                exit(EXIT_SUCCESS);
            }

3 否则,我们一定在父进程中:
            else
            {
                data_processed = write(file_pipes[1],some_data,strlen(some_data));
                printf("Wrote %d bytes/n",data_processed);
            }
        }
        exit(EXIT_SUCCESS);
        }

当我们运行这个程序,我们得到与前面一样的输出:

$ ./pipe2
Wrote 3 bytes
Read 3 bytes: 123

我们也许会发现实际上命令提示符会在输出的最后部分之前出现,但是我们在这里已经对输出进行整理从而使其更易于阅读。

工作原理

首先这个程序使用pipe调用创建一个管道。然后他使用fork调用来创建一个新的进程。如果fork调用成功,父进程就会向管道写入数据,而子进程由管道中读取数据。父子进程都会在一个简单的write与read之后退出。如果父进程在子进程之前退出,我们就会看到shell提示符出现在两个输出之间。

尽管这个程序与前面的管道例子十分相似,但是我们已经通过使用单独的进程用于读写而向前进了一大步.


http://www.coolblog.cn/news/e630a5d00d798597.html

相关文章:

  • asp多表查询并显示_SpringBoot系列(五):SpringBoot整合Mybatis实现多表关联查询
  • s7day2学习记录
  • 【求锤得锤的故事】Redis锁从面试连环炮聊到神仙打架。
  • 矿Spring入门Demo
  • 拼音怎么写_老师:不会写的字用圈代替,看到孩子试卷,网友:人才
  • Linux 实时流量监测(iptraf中文图解)
  • Win10 + Python + GPU版MXNet + VS2015 + RTools + R配置
  • 美颜
  • shell访问php文件夹,Shell获取某目录下所有文件夹的名称
  • 如何优雅的实现 Spring Boot 接口参数加密解密?
  • LeCun亲授的深度学习入门课:从飞行器的发明到卷积神经网络
  • Mac原生Terminal快速登录ssh
  • java受保护的数据与_Javascript类定义语法,私有成员、受保护成员、静态成员等介绍...
  • mysql commit 机制_1024MySQL事物提交机制
  • 支撑微博千亿调用的轻量级RPC框架:Motan
  • jquery 使用小技巧
  • 2019-9
  • 法拉利虚拟学院2010 服务器,法拉利虚拟学院2010
  • vscode pylint 错误_将实际未错误的py库添加到pylint白名单
  • 科学计算工具NumPy(3):ndarray的元素处理
  • 工程师在工作电脑存 64G 不雅文件,被公司开除后索赔 41 万,结果…
  • linux批量创建用户和密码
  • newinsets用法java_Java XYPlot.setInsets方法代碼示例
  • js常用阻止冒泡事件
  • 气泡图在开源监控工具中的应用效果
  • 各类型土地利用图例_划重点!国土空间总体规划——土地利用
  • php 启动服务器监听
  • dubbo简单示例
  • 【设计模式】 模式PK:策略模式VS状态模式
  • [iptables]Redhat 7.2下使用iptables实现NAT
  • Ubuntu13.10:[3]如何开启SSH SERVER服务
  • CSS小技巧——CSS滚动条美化
  • JS实现-页面数据无限加载
  • 阿里巴巴分布式服务框架 Dubbo
  • 最新DOS大全
  • Django View(视图系统)
  • 阿里大鱼.net core 发送短信
  • 程序员入错行怎么办?
  • 两张超级大表join优化
  • 第九天函数
  • Linux软件安装-----apache安装
  • HDU 5988 最小费用流
  • Sorenson Capital:值得投资的 5 种 AI 技术
  • 《看透springmvc源码分析与实践》读书笔记一
  • 正式开课!如何学习相机模型与标定?(单目+双目+鱼眼+深度相机)
  • Arm芯片的新革命在缓缓上演
  • nagios自写插件—check_file
  • python3 错误 Max retries exceeded with url 解决方法
  • 行为模式之Template Method模式
  • 通过Spark进行ALS离线和Stream实时推荐