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

linux进程间通信:无名管道 pipe

文章目录

      • 内核层实现
        • 结构
        • 通信原理
        • 特点
      • 使用
        • 函数声明
        • 使用实例
          • 单向通信
          • 双向通信
        • 编程注意事项
          • 管道中无数据时读操作会阻塞
          • 将管道的写端句柄关闭,不会影响读端数据读取
          • 管道中没有数据,写操作关闭则读操作会立即返回
          • 管道大小测试 64K
          • 管道发生写满阻塞,一旦有4k空间,写继续
      • 总结

内核层实现

结构

Linux操作系统中的无名管道结构如下图:
在这里插入图片描述
管道在内核中的实现即如一个缓冲区,内核提供将该缓冲区以一个文件句柄的形式提供给用户态供其调用,进程1使用文件句柄f[0]读,进程2使用文件句柄f[1]写。

无名管道的数据结构声明文件pipe_fs_i.h
执行命令locate pipe_fs_i.h即可找到该文件路径,查看管道文件描述符如下,由于我的内核版本较新,可能该声明和其他版本差异较大:

/***      struct pipe_inode_info - a linux kernel pipe*      @mutex: mutex protecting the whole thing*      @wait: reader/writer wait point in case of empty/full pipe*      @nrbufs: the number of non-empty pipe buffers in this pipe*      @buffers: total number of buffers (should be a power of 2)*      @curbuf: the current pipe buffer entry*      @tmp_page: cached released page*      @readers: number of current readers of this pipe*      @writers: number of current writers of this pipe*      @files: number of struct file referring this pipe (protected by ->i_lock)*      @waiting_writers: number of writers blocked waiting for room*      @r_counter: reader counter*      @w_counter: writer counter*      @fasync_readers: reader side fasync*      @fasync_writers: writer side fasync*      @bufs: the circular array of pipe buffers*      @user: the user who created this pipe**/struct pipe_inode_info {struct mutex mutex;wait_queue_head_t wait;unsigned int nrbufs, curbuf, buffers;unsigned int readers;unsigned int writers;unsigned int files;unsigned int waiting_writers;unsigned int r_counter;unsigned int w_counter;struct page *tmp_page;struct fasync_struct *fasync_readers;struct fasync_struct *fasync_writers;struct pipe_buffer *bufs;struct user_struct *user;
};

通信原理

  • 管道的内核封装 是一个文件(pipefs):
    a. 内核将一个缓冲区与管道文件进行关联、封装
    b. 用户通过open/read/write/close等IO接口进行读写

    读写过程如下所示,进程运行时使用管道会默认打开一些文件句柄包括标准输入流/输出流/错误 等。
    在这里插入图片描述

特点

  • 像一个管道连接两个进程
  • 一个进程作为输入,一个进程作为输出
  • 用于亲缘关系进程之间的通信:共享资源
    在这里插入图片描述

使用

函数声明

  • int pipe(int pipefd[2]);
  • int pipe(int pipefd[2],int flags);

成功返回0,失败返回-1

函数空间主要包含两个文件描述符,一个用来读,一个用来写
详细信息可以通过man 2 pipe查看系统调用信息

使用实例

单向通信

实现方式如下
在这里插入图片描述
代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>#define handle_error(msg)\
{perror(msg);exit(-1);}int main()
{int pipe_fd[2];if (pipe(pipe_fd) == -1) //创建管道handle_error("pipe");int f;f = fork();if (f == -1)handle_error("fork");if(f == 0){char str[100] = {0};printf("child process input :\n");scanf("%s",str);write(pipe_fd[1],str,strlen(str)); //子进程向管道写内容close (pipe_fd[1]);_exit(0);}if (f > 0){char buf[100] = {0};read (pipe_fd[0],buf,30);printf("parent process output : %s\n",buf); //父进程从管道读内容close(pipe_fd[0]);_exit(0);}return 0;
}

输出如下:

zhang@ubuntu:~/test$ gcc test_pipe.c -o test_pipe
zhang@ubuntu:~/test$ ./test_pipe 
child process input :
aa
parent process output : aa
双向通信

实现方式如下,父进程和子进程之间既可以读也可以写,该实现是通过两个管道进行读写处理。
在这里插入图片描述
代码实现如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>#define handle_error(msg)\
{perror(msg);exit(-1);}int main()
{int pipe_fd[2];int pipe_fd2[2];if (pipe(pipe_fd) == -1 || pipe(pipe_fd2)) //创建两个管道handle_error("pipe");int f;f = fork();if (f == -1)handle_error("fork");if(f == 0) //子进程处理,子进程先写pipe_fd[1],再读pipe_fd[0]{char str[100] = {0};char str2[100] = {0};printf("child process input :\n");scanf("%s",str);write(pipe_fd[1],str,strlen(str));close (pipe_fd[1]);read(pipe_fd2[0],str2,100);printf("in child process read : %s\n",str2);close(pipe_fd2[0]);_exit(0);}if (f > 0) //父进程和子进程相反,先读pipe_fd[0],再写pipe_fd2[1]{char buf[100] = {0};char buf2[100] = {0};read (pipe_fd[0],buf,30);printf("parent process output : %s\n",buf);close(pipe_fd[0]);printf("in parent process write: \n");scanf("%s",buf2);write(pipe_fd2[1],buf2,strlen(buf2));_exit(0);}return 0;
}

最终输出如下:

zhang@ubuntu:~/test$ ./test_pipe_double 
child process input :
hello
parent process output : hello
in parent process write: 
world
zhang@ubuntu:~/test$ in child process read : world

编程注意事项

管道中无数据时读操作会阻塞

如下代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{int fd[2];char buf[50] = {0};//缓存if(pipe(fd)!=0)// 创建无名管道{perror("pipe fail: ");exit(1);}printf("%d %d\n",fd[0],fd[1]);//打开的文件描述符,此处为3,4 默认打开 0,1,2,标准输入,输出,出错//管道中没有数据的时候读阻塞//  write(fd[1],"hello",10);  //此处不向管道写数据时,读操作会阻塞,管道中有数据时,读操作后结束进程read(fd[0],buf,10);printf("%s",buf);putchar(10); // '\n'return 0;
}

输出如下
在这里插入图片描述

将管道的写端句柄关闭,不会影响读端数据读取

代码如下

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{int fd[2];char buf[50] = {0};//缓存if(pipe(fd)!=0)// 创建无名管道{perror("pipe fail: ");exit(1);}printf("%d %d\n",fd[0],fd[1]);//打开的文件描述符,此处为3,4 默认打开 0,1,2,标准输入,输出,出错//管道中没有数据的时候读阻塞write(fd[1],"hello",10);  //此处不向管道写数据时,读操作会阻塞,管道中有数据时,读操作后结束进程close(fd[1]);read(fd[0],buf,10);close(fd[0]);printf("%s",buf);putchar(10); // '\n'return 0;
}

输出正常如下:

zhang@ubuntu:~/test$ ./a.out 
3 4
hello
管道中没有数据,写操作关闭则读操作会立即返回

测试代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{int fd[2];char buf[50] = {0};//缓存if(pipe(fd)!=0)// 创建无名管道{perror("pipe fail: ");exit(1);}printf("%d %d\n",fd[0],fd[1]);//打开的文件描述符,默认打开 0,1,2//写端关闭,管道中无数据,读操作立即返回close(fd[1]);read(fd[0],buf,5);return 0;
}
zhang@ubuntu:~/test$ ./a.out 
3 4
管道大小测试 64K
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{int fd[2];char buf[65536] = {0};//缓存if(pipe(fd)!=0)// 创建无名管道{perror("pipe fail: ");exit(1);}int f = fork();int num = 0;if (f == 0) {int ret = write(fd[1],"123",1024);while (1 && ret != 0){ret = write(fd[1],"123",1024);printf("write size is %d\n",ret);num ++;printf("write count is %d\n",num);}close(fd[1]);_exit(1);}if (f > 0){printf("%d %d\n",fd[0],fd[1]);//打开的文件描述符,默认打开 0,1,2//写端关闭,管道中无数据,读操作立即返回read(fd[0],buf,65536);printf("write result is %s\n",buf);close(fd[0]);_exit(1);}return 0;
}

输出如下,当写入数据达到64K时会阻塞

write count is 63
write size is 1024
write count is 64
...
管道发生写满阻塞,一旦有4k空间,写继续
include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{int fd[2];char buf[65536] = {0};//缓存if(pipe(fd)!=0)// 创建无名管道{perror("pipe fail: ");exit(1);}int f = fork();int num = 0;if (f == 0) {int ret = write(fd[1],"123",1024);while (1 && ret != 0){ret = write(fd[1],"123",4096);printf("write size is %d\n",ret);num ++;printf("write count is %d\n",num);}close(fd[1]);_exit(1);}if (f > 0){sleep(1);printf("get the wirte result is %d %d\n",fd[0],fd[1]);//打开的文件描述符,默认打开 0,1,2//写端关闭,管道中无数据,读操作立即返回read(fd[0],buf,4096);printf("write result is %s\n",buf);close(fd[0]);_exit(1);}return 0;
}

输出如下

write count is 15
get the wirte result is 3 4 //读出来一次,
write result is 123 
zhanghuigui@ubuntu:~/test$ write size is 4096  子进程继续写入读出的空间
write count is 16 //写满后又发生了阻塞
...  

总结

综上可见,管道是应用在拥有亲缘关系的进程之间的共享资源。
优点也很明显:
管道属于系统调用,且数据存放在内存之中,它的父子进程通信过程效率非常高
缺点同样也很明显:
父子进程通信交互并不友好,阻塞式的通信非常影响用户体验

相关文章:

争吵所达到的效果要_悟空:不要害怕争吵,有时候争吵一些不喜欢的事情也能创造和谐...

悟空&#xff1a;八戒&#xff0c;你吃了早饭去把马喂了吧。八戒&#xff1a;好的。悟空&#xff1a;喂了马你去看看我们午饭可以吃什么&#xff0c;如果有需要提前做预备的什么事儿&#xff0c;你知道该怎么做吧&#xff1f;八戒&#xff1a;好的。悟空&#xff1a;昨天&#…

Log4j日志管理的用法

参考网址&#xff1a; http://www.blogjava.net/314508313/archive/2011/11/14/363653.html http://www.cnblogs.com/likwo/archive/2010/09/01/1814994.html http://fanqiang.chinaunix.net/app/other/2006-06-22/4640.shtml http://www.blogjava.net/rickhunter/articles/281…

多线程实现生产者消费者模型

首先是一个仓库接口&#xff0c;该接口规定的仓库大小&#xff0c;仓库的存取方法&#xff0c;如下所示 1 package pers.lan.jc.pc;2 3 /**4 * author lan [1728209643qq.com]5 * create 2018-11-27 15:596 * desc 仓库7 */8 public interface Repertory<T> {9 10 …

再记一次ceph object unfound的艰辛历程

文章目录先说问题&#xff1a;再说解决尝试1&#xff1a;尝试2(该尝试建议先在自己环境搭配对应业务测试通过后再现场尝试)&#xff1a;感谢 学无止境996同学的陪伴和vigourtyy美丽女友的支持&#xff0c;直到这个解决问题的深夜先说问题&#xff1a; ceph 12.2.1生产环境&…

2014-01-04 SQL练习

目标数据库 250,czzznew/czzznew *关于执行计划&#xff1a;在PL/SQL选中查询的语句后&#xff0c;按下F5即可&#xff0c;其中Cost列表示当前操作的代价&#xff08;消耗&#xff09;&#xff0c;值越大代表性能越差 t_rkxx表 (1):用2种以上方法查出xm(姓名)为test或者Test的人…

多重集表示合json数据_计数DP(划分数,多重集组合数)

划分数&#xff1a;把n个无区别的物品划分成不超过m组。 dp[i][j]j的i划分的总数。 dp[i[j]dp[i][j-i]dp[i-1][j] 即&#xff1a;将j个物品分成i份&#xff0c;有两种情况&#xff1a;每份划分都大于等于1 dp[i][j-i]; 存在有一份以上用0划分dp[i-1][j]int main(){int n,m;cin&…

搭建PHP环境遇到的问题!!

为什么80%的码农都做不了架构师&#xff1f;>>> 问题1&#xff1a; 再次./configure以下错误发生 configure: error: xml2-config not found. Please check your libxml2 installation. 解决方法&#xff1a; 安装libxml2 # yum install libxml2-devel 问题2&…

linux进程间通信:shell管道 | 的实现

文章目录介绍重定向函数介绍总结linux terminal输入如下命令&#xff0c;其中"|"符号即为我们上文中所说的无名管道介绍 正如我们上文中所描述的"|“无名管道提供了具有亲缘关系的进程之间的通信&#xff0c;它由于直接使用系统调用&#xff0c;运行效率较高。…

Golang的接口

当一只鸟走路像鸭子&#xff0c;游泳像鸭子&#xff0c;叫起来也像鸭子&#xff0c;那么我们就认为它就是鸭子。 Duck typing 的理念因此比喻得名。 Golang 通过 interface 实现 duck typing。 Effective Go 文章中这样描述 interface: interface 指定了一种描述对象行为的方法…

mysql 5.6.15_mysql-5.6.15-win32.zip免安装配置

此随笔是根据网上的资料整理的&#xff1a;环境&#xff1a;Windows XP系统软件来源&#xff1a;mysql官网下载1.下载mysql-5.6.15-win32.zip&#xff1b;2.解压MySQL压缩包&#xff1b;以下以加压到“F:\Program Files\Mysql\mysql-5.6.15-win32”为例&#xff1a;3.将解压目录…

jquery treeview 树形插件

jquery treeview 插件参数说明 treeview开源地址&#xff1a;https://github.com/jzaefferer/jquery-treeview 1、animated&#xff1a;String or Number 设置展开子节点时的显示速度&#xff0c;有 slow、normal、fast 或者指定速度值&#xff0c;与 jQuery 的 hide&#xff0…

spark调优(一)-开发调优,数据倾斜,shuffle调优

主要分为开发调优、资源调优、数据倾斜调优、shuffle调优几个部分。 开发调优和资源调优是所有Spark作业都需要注意和遵循的一些基本原则&#xff0c;是高性能Spark作业的基础&#xff1b;数据倾斜调优&#xff0c;主要讲解了一套完整的用来解决Spark作业数据倾斜的解决方案&am…

linux进程间通信:popen函数通过管道与shell通信

函数描述 FILE *popen(const char* command,const char* type) 该函数的执行过程如下&#xff1a; a. 调用pipe创建一个管道&#xff0c;并fork创建一个子进程来执行shell,shell会创建一个子进程来执行commad b. 将父进程的输入输出重定向到管道&#xff0c;建立一个单向的数据…

新的小游戏发布啦。Pop Jungle

丛林爱消除是一款画面清新&#xff0c;效果绚丽的消除类休闲游戏。你只需要选中尽可能多的图块&#xff0c;并消除它们就可以得到高分&#xff0c;并有无限多的关卡等待你去征服。一旦你开始玩儿你将无法停止下来&#xff0c;如果你还是消除星星的粉丝&#xff0c;那你更加不能…

mysql thread safe_Windows环境下完全手工配置Apache、MySQL和PHP(Thread Safe)

happydagui&#xff1a;现在LAMP(Linux、Apache、MySQL、PHP/Perl/Python的简称)已经很流行了。在Windows下也有类似的&#xff0c;比如 WAMP(Apache, MySQL, PHP on Windows)。这篇文章主要是介绍如何在Windows环境下完全手工配置Apache、MySQL和PHP&#xff0c;都是解压后直接…

点滴积累【C#】---检验编号在本表中自动生成,与其他表无关

检验编号在本表中自动生成&#xff0c;与其他表无关 效果&#xff1a; 描述&#xff1a;在本表中自动生成编号&#xff0c;与其他表无关。 调用&#xff1a; 1 protected void Page_Load(object sender, EventArgs e)2 {3 Response.Expires -1;4 …

Alpha冲刺(9/10)

团队信息 队名&#xff1a;爸爸饿了组长博客&#xff1a;here作业博客&#xff1a;here组员情况 组员1&#xff08;组长&#xff09;&#xff1a;王彬 过去两天完成了哪些任务 学习jQuery的AJAX部分的基础知识,对web端如何异步获取服务器信息有了初步认识接下来的计划 & 还…

linux进程通信:pipe实现进程同步

文章目录通过管道同步进程实现代码管道缓冲区设置缓冲区大小总结 &#xff1a;pipe的特点通过管道同步进程 管道自带同步互斥机制&#xff1a; 管道的内核实现&#xff1a;fs/pipe.c &#xff0c;主要通过内核的锁以及等待队列等机制实现 管道的write操作会阻塞进程 当内存缓冲…

(转)MySQL联表查询

资料源于网络 一.内联结、外联结、左联结、右联结的含义及区别在SQL标准中规划的&#xff08;Join&#xff09;联结大致分为下面四种&#xff1a;1.内联结&#xff1a;将两个表中存在联结关系的字段符合联结关系的那些记录形成记录集的联结。2.外联结&#xff1a;分为外左联结和…

极小连通子图和极大连通子图_强连通分量与拓扑排序

前言由于GacUI里面开始多处用上拓扑排序&#xff0c;我决定把之前瞎JB搞出来的算法换掉&#xff0c;换成个正式的。之前我自己弄了个写起来很简单的算法&#xff0c;然后每一处需要用到的地方我就重新做一遍。当然这样肯定也是不行的&#xff0c;我觉得也差不多积累到重构的临界…

INTERVAL数据类型-007学习笔记

http://baggio785.itpub.net/post/31233/286119 INTERVAL数据类型用来存储两个时间戳之间的时间间隔。 可以指定years and months&#xff0c;或者days,hours,minuts,seconds之间的间隔。本文为oracle的学习笔记&#xff0c;结合实例介绍INTERVAL数据类型。 INTERVAL数据类型用…

scrapy模拟用户登录

scrapy框架编写模拟用户登录的三种方式&#xff1a; 方式一&#xff1a;携带cookie登录&#xff0c;携带cookie一般请求的url为登录后的页面&#xff0c;获取cookie信息应在登录后的页面获取&#xff0c;cookie参数应转成字典形式 # -*- coding: utf-8 -*- import re import sc…

linux 系统调用 open函数使用

函数介绍 本文仅仅将open系统调用的使用简单总结一下&#xff0c;关于其实现原理大批的大佬分享可以自行学习。open系统调用主要用于打开或者创建一个文件&#xff0c;并返回文件描述符。 头文件 #include <fcntl.h>函数名称 a. int open(const char *pathname, int fl…

配置zendframework开始工作(加入环境变量)

首先需要把把两个路径加入到环境变量中 1、我用的php环境是xampp&#xff0c;安装在di盘&#xff0c;我要把d:/xampp/php/这个路径加入到环境变量 2、下载zendframework&#xff08;我用的版本是1.&#xff09;,把安装包中的bin目录加入到环境变量 3、关于设置php/php.ini中设置…

mysql计算两gps坐标的距离_mysql 计算两坐标间的距离

mysql 5.6.1 加入了空间数据支持功能&#xff0c;新增了st_*相关函数&#xff0c;可以非常方便的计算两个地理坐标点的距离了。如下例子&#xff1a;按我的坐标计算周边坐标的距离并由近到远排序select name,st_distance(point(113.327955,23.129717),point)*111195 as distanc…

(转)mxArray数据类型

1 、数据类型mxArray的操作 在上节的Matlab引擎函数中&#xff0c;所有与变量有关的数据类型都是mxArray类型。数据结构mxArray以及大量的mx开头的函数&#xff0c;广泛用于Matlab 引擎程序和Matlab C数学库中。mxArray是一种很复杂的数据结构&#xff0c;与Matlab中的array相对…

Bootstrap笔记(记录不会的知识)

head&#xff1a; <link rel"stylesheet" href"bootstrap.min.css" /> 引入bootstrap.min.css文件 <meta name"viewport" content"widthdevice-width,initial-scale1" /> content"widthdevice-width&#xff1a;设为…

linux 系统调用 read,write和lseek 使用

read系统调用 头文件 #include <unistd.h>函数使用 ssize_t read(int fd, void *buf, size_t count) read 函数会从文件描述符fd中读取指定的count长度的内容&#xff0c;并且将读到的结果放入到buf缓冲区中返回值 count 读取成功&#xff0c;则会返回读到的字节数 小于…

简单有趣的matlab小程序_超实用有趣的五个小程序推荐

大家好&#xff0c;我是小胖。废话不多说&#xff0c;进入正题。1.一周CP共读有趣的灵魂总会相遇。一个极简的社交小程序。通过选择自己喜欢的一本书&#xff0c;匹配到那个跟自己有着一样有趣灵魂的TA。选择好要阅读哪本书之后&#xff0c;填写下资料&#xff0c;就能在看一本…

一些linux下的性能监测工具

1.gprof http://blog.csdn.net/stanjiang2010/article/details/5655143 2.系统性能调优 http://www.ibm.com/developerworks/cn/linux/l-time/part2/index.html?cadrs perf http://www.ibm.com/developerworks/cn/linux/l-cn-perf1/ oprofile http://www.ibm.com/developerwor…