(转)关于pipe()的详细解析

深入解析 Go 中的 `io.Pipe()`:实现高效的并发通信 io.Pipe()是 Go 语言中一个非常有用的工具,用于在不同的 goroutine 之间实现高效的同步和通信。通过创建一对连接的 I/O 流,可以实现数据的安全传递。这种机制在处理并发任务时非常有用,例如在管道中传递数据、实现生产者-消费者模式等。希望本文的介绍和示例代码能够帮助你更好地理解和使用io.Pipe(),提升你的 Go 编程能力。如果你有任何疑问或建议,欢迎在评论区留言,我们一起交流学习! 阅读详情

                                   kevintz 2000.8.23
    int pipe(int fd[2])函数在内核生成一个管道,如图。返回的
fd[0]描述符用于从管道读内容,fd[1]用于向管道写。
               ---------------------
       fd[0]<--| |<---fd[1]
---------------------
读的时候,如果管道没数据,读进程阻塞。如果写的时候管道满,
写进程阻塞。可以把fd[0], fd[1]设成是非阻塞,在上面的阻塞情形,
不再阻塞进程,立刻返回。
管道的某一端只能是只读或只写,如果向fd[0]写和向fd[1]读都会
出错,返回-1。
另外,fork()调用生成的子进程和原来的父进程是共用这条管道的,
并不是又生成另一条管道。如图所示:
+------------------------+
| |
------------- +- ----------- <-----+ | -----------
父 | fd[0] |<----- | | <---+ | +->| fd[0]   | 子
     |           |        -----------     |  |    |         |         
     |   fd[1]   |------------------------+  +--- |  fd[1]  |
     | ........  |                                | .....   |
    而且对于子进程来说,fd[0]也是用于只读,fd[1]也是用于写,因为
它们的指向和父进程里是一样的。
    下面来分析一下网友startrek写的程序,并分析为何出错。
int main(){
  int  fd[2];
  char buf[200],len;
  int  status;
  if(pipe(fd)==0){
    if(fork()==0){
      len=read(fd[0],buf,sizeof(buf));
      buf[len]=0;
      printf("[Child]:%s/n",buf);
      sprintf(buf,"answer from child");
      write(fd[1],buf,strlen(buf));
    }
    else{
      sprintf(buf,"string from parent");
      write(fd[1],buf,strlen(buf));
      sleep(2);
      len=read(fd[0],buf,sizeof(buf));    // ***
      buf[len]=0;
      printf("[Parent]:%s/n",buf);
    }
  }
  wait(&status);
}
[情况1]
  如果注释掉sleep(2);这一句,父进程就会接收自己传给子进程的
  字符串,显示
  [Parent]:string from parent
  而子进程就因为无数据读而阻塞。这说明父进程和子进程之间只有
  一条管道队列进行双向传输,父进程读取数据后管道为空,所以子
  进程阻塞。
kevintz分析:其实这个结果是正确的。原因如下:去掉sleep(2)后,当父进
程写fd[1]后,继续运行read(..),所以父进程把自己写进去的东西读
了出来。而到子进程运行时,就因为没数据读而阻塞了。注意:管道
只能是单向传输的!
[情况2]
  但如果将标有***的一句改为
  len=read(fd[1],buf,sizeof(buf)),而sleep(2);不注释,就会有
  下面奇怪的显示结果:
  [Child]:string from parent
  [Parent]:string from parent
  按道理说在子进程退出后,管道中应该只有"answer from child"。
kevintz分析:这个结果也是正确的。其实子进程是已经读到了父进程的内容,
而且已经写回了管道里。不过因为不论是父进程还是子进程对fd[1]读,
都是出错的,返回-1,而buf里的东西还是sprintf进去的东西,没变。
反而buf[len]就是buf[-1]=0这句有潜在的危险。然后你把buf打印,所
以还是原来的内容。管道的某一端都只能是只读或只写的!
[情况3]
  和情况2相同,在最后加3行,即父进程使用fd[0]进行read,其
  显示结果为
  [Child]:string from parent
  [Parent]:string from parent
  [Parent]:answer from child
kevintz分析:这个例子就正好做了情况2的解析。说明子进程的确收到了父进程
的信息,而且写回了管道,而父进程应该用read(fd[0]...)来读的,所
以读到了子进程写回的信息。
[情况4]
  如果一开始父进程多传一个串"string 2 from parent",其结果
  就更复杂。
kevintz分析:呵呵:),多传一个串,结果慢慢去分析吧................
总结:
    其实这种通信,应该用两条管道来形成一个双向的交流管道,而不应该用一
条管道。
    当然你可以用信号量来同步管道的使用,但太复杂,而且不实际。双向管道
可以这样实现。
int main()
{
    int fd1[2],fd2[2],len;
    char buf[128];
    int status;
    pipe(fd1);
    pipe(fd2);
    if( fork() == 0)
    {
       close(fd1[0]);
       close(fd2[1]);
       len=read(fd2[0], buf, 128);
       buf[len]=0;
       printf("[Child]:%s/n",buf);
       sprintf(buf,"answer from child");
       write(fd1[1], buf, strlen(buf));
       close(fd2[0]);
       close(fd1[1]);
    }
    else
    {
       close(fd1[1]);
       close(fd2[0]);
       sprintf(buf, "Hello from parent");
       write(fd2[1], buf, strlen(buf));
       len=read(fd1[0],buf,sizeof(buf));    
       buf[len]=0;
       printf("[Parent]:%s/n",buf);
       close(fd1[0]);
       close(fd2[1]);
    }
    wait(&status); 
    exit(0);
}
--
※ 修改:.kevintz 于 Aug 23 11:08:13 修改本文.[FROM: 61.140.71.100]

PIPE Interface解析之PIPE SerDes/Original架构 PIPI Interface;SerDes架构;Original架构;PHY Tx结构;PHY Rx结构; 阅读详情

相关推荐

PIPE Interface解析之PIPE介绍

PIPE Interface;PIPE5.2简介;PCIe PHY Layer;

weixin_45176819的博客 3830

主题:《Linux内核模块编程指南》(五)

主题:《Linux内核模块编程指南》(五)发信人: kevintz()整理人: kevintz(2000-06-24 00:40:31), 站内信件《Linux内核模块编程指南》《Linux Kernel Module Programming Guide》作者:Ori Pomerantz 中译者:谭志(lkmpg@21cn.com)

robinshaw的专栏 1203

pipe()——进行文件复制

使用pipe()处理大文件 在使用大文件复制的案例中,通过可读流的chunk参数来传递数据,如果把数据比作是水,这个chunk就相当于盆,使用盆来完成水的传递。在可读流中还有一个函数叫作pipe(),这个函数是一个很高效的文件处理方式,可以简化之前复制文件的操作,pipe翻译成中文是管子的意思,使用pipe()进行文件复制相当于把盆换成管子,通过管子来完成数据的读取和写入。 下面通过案例来演示如何...

weixin_43446193的博客 749

linux 管理 suid sgid 用法

一、UNIX下关于文件权限的表示方法和解析   SUID 是 Set User ID, SGID 是 Set Group ID的意思。   UNIX下可以用ls -l 命令来看到文件的权限。用ls命令所得到的表示法的格式是类似这样的:-rwxr-xr-x 。下面解析一下格式所表示的意思。这种表示方法一共有十位:   9 8 7 6 5 4 3 2 1 0 - r w x r

zheng195X的专栏 500

Spark转换算子之sortBy()算子和pipe()算子

sortBy() 代码实现 pipe()调用脚本 编写脚本 #!/bin/sh echo "Start" while read LINE; do echo ">>>"${LINE} done 打开脚本 创建一个只有一个分区的RDD val rdd = sc.makeRDD (List("hi","Hello","how","are","you"),1) 将脚本作...

SmallScorpion 1030

ArcGIS拓扑面错误批量修改

在工作学习中经常会遇到拓扑修改的问题,当数据量巨大的时候会产生拓扑问题 当拓扑错误数量巨大时,人工逐一修改是不现实的,基于此利用gis自带工具箱实现拓扑面类错误的批量修改。 一、.常见拓扑错误的类型: 1面重叠 2空隙(绿色部分) 二、拓扑检查 1新建数据库-----新建数据集—导入数据. 2新建拓扑 3修改拓扑容差及名称 添加拓扑修改规则 完成拓扑检查-查看拓扑错误 三、拓扑批量...

qq_43173805的博客 3万+

C中一种函数声明方式及可变参数函数讨论

本文部分原创,部分改编 可变参数函数改编自:网友kevintz的“C语言中可变参数的用法”一文 #include //引入可变参数函数头文件 #include //C语言中另一种函数声明方式 print(uint,buf,len) int uint; int buf; int len; { printf("Function Declaration another Way Result1

夜之流萤 451

论文阅读—Square Attack: a query-efficient black-box adversarial attack via random search

论文阅读—Square Attack: a query-efficient black-box adversarial attack via random search 发表位置 ECCV 2020 摘要 作者提出了一种基于得分的黑盒Square attack,该模型不依赖于模型的局部梯度信息,因此可以绕过梯度隐藏防御攻击。Square Attack是一种随机搜索方法,它在随机位置选择局部的方形更新,使得每次迭代时扰动近似位于可行集的边界。 背景 当涉及到对安全至关重要的机器学习应用时,对抗性的例子尤其值得

yayayamaomaoya的博客 2494

可变参数学习笔记

前言:本文在很大程度上改编自网友kevintz的“C语言中可变参数的用法”一文,在行文之前先向这位前辈表示真诚的敬意和感谢。一、什么是可变参数我们在C语言编程中有时会遇到一些参数个数可变的函数,例如printf()函数,其函数原型为: int printf( const char* format, ...); 它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的(

laomai的专栏 9239

【HAL库-STM】智能温控按键小风扇【胎教级教学】

硬件设备:DHT11,0.96寸oled屏,二/三/四线风扇(不挑),面包板 、f10的精英板等等。当人在的风扇面前时可以自行控制风扇,不在面前时又想开风扇就让他温控自行开启,(在这里有一个想法就是加上蓝牙和wifi控制的功能能够远程遥控,这个如果做的再全一点就要自主研发是一个多功能app,这里没有做。针对这个dht11,我一开始是卡在了这个check函数里面,一直是我给完dht11低电平和高电平后,dht11不回复我低电平和高电平,这个不是我的问题,当时代码是没毛病的,这个点一直卡着我。吐血五天实现小成品

weixin_52451652的博客 1740

Claude Code 错误解决方案 API Error: 前缀通用错误

本文分析了Claude Code与Anthropic API通信时出现的通用错误处理问题。当API返回未分类错误时,系统会直接显示"API Error: "前缀的原始错误信息。通过错误链路追踪发现,这是由于未匹配特定错误类型时触发了通用兜底处理逻辑。文章提供了三种解决方案:查看具体错误内容、启用调试日志以及提交问题反馈,并建议用户关注错误码、使用/compact命令处理上下文超限问题。最后强调这些未分类错误是预期行为,用户应通过错误消息中的线索自行排查或反馈开发者。

多媒体编程、网络编程、系统编程、网络安全编程、驱动编程 1349

学习笔记 -- pipe 管道问题记录

管道是进程间通信的方法之一,也是很简单的一种方法 父进程通过系统调用 pipe(int fd[2]) 在内核空间创建的一个管道,并且 fd[1], fd[2] 分别代表了读端和写端。父进程再 fork() 出一个子进程,那么子进程也拥有了该管道的读端与写端。注意:管道为半双工,如果要进行全双工通信,需要两个管道 然后,如果父进程向子进程进行通信,那么需要经过如下几个过程 parent: close(fd[0]) // 父进程关闭读端 parent: write(fd[1], &buf, size

qq_39274501的博客 973

YOLOv11改进策略【卷积层】| CVPR2025 GBConv轻量门控瓶颈卷积 低秩瓶颈降参 + 门控聚焦形态,强效捕捉纤细目标

裂缝形态不规则、纹理纤细,传统卷积参数大、计算冗余,且无法动态聚焦裂缝形态;背景噪声强易干扰特征提取,需要轻量且能自适应聚焦裂缝形态的卷积单元,因此提出轻量门控瓶颈卷积 GBC。

Limiiiing的博客 853

pipe()函数详解

管道概述 管道也叫无名管道,它是UNIX系统IPC(进程间通信)的最古老形式,所有的UNIX系统都支持这种机制。 无名管道特点 1.半双工,数据在同一时刻只能在一个方向上流动 2.数据只能从管道的一端写入,从另一端读出 3.写入管道的数据遵循先入先从出的规则 4.管道所传送的数据不是无格式的,这要求管道的读出方和写入方必须约定好数据的格式,如多少字节算一个消息 5.管道不是普通的文件,不属于某个文件系统,其只存在于内存中 6.管道在内存中对应一个缓冲区,不同的系统其大小不一定相同 7.从管道读数据是一次性操

Orange的博客 1万+

Python-编写点云处理软件(二)点云软件ui制作之仿CC界面

至本篇结束,我们已经能够获得一个有点模子的界面了,但是具体的功能还没有编写,后续的文章将逐渐完善功能。

weixin_43894929的博客 3953

【异常】Claude Code CLI工具 模型加载异常 /init报错排查与完整解决方案 There‘s an issue with the selected model (glm-5). It

此类跨厂商模型配置报错,核心诱因是API生态的兼容性不匹配。优先使用工具原生支持的模型体系,可快速解决90%以上的同类报错;若需跨厂商使用目标模型,需完成API端点、鉴权密钥、模型ID的全链路适配,确保全流程配置合规,即可完成异常修复。

奶爸的编程之路,也就一周冷个三天 3704

系统调用--fork()与pipe()

今天开始做操作系统的实验,遇到了之前听过但是从未深入研究过的知识,所以今天打算对涉及到的知识进行深入的总结,话不多说,开始吧!

qq_74390043的博客 1183

Python爬招聘网站:Selenium+ActionChains破解滑动验证码,批量采集岗位数据(新手可跑)

通过本文实战,你不仅学会了用Selenium+ActionChains破解滑动验证码,还掌握了爬虫的核心优化思路——“模拟人类行为”是突破反爬的关键。这套逻辑不仅适用于招聘网站,还能迁移到其他有滑动验证码的平台(如电商、资讯网站)。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1188

pandas管道函数pipe

1.概述 在操作Series或者DataFrame级别数据时,例如修改、删除等,需要用到一些特别的函数,常用的有下面几个: 1.apply():以DataFrame的行或列为单位(由axis参数决定),操作数据。 2.applymap():操作DataFrame中的每个元素。 3.map():操作Series,或者DataFrame中某一列的元素。 4.pipe():操作整个DataFrame或者 Series中的所有元素。 2.pipe介绍 相对来说,前面三个函数理解起来,相对较为容易。最不

qiuqiuit的专栏 3743

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

管道-pipe()函数使用

进程间通信 linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。 进程间通信的方式 在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件、管道、信号、共享内存、消息队列、套接字、命名管道

weixin_46211877的博客 2738

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

python multiprocessing.Pipe的close()问题

主要讲close问题,和recv卡住问题 recv卡住是因为他要等待管道中有数据接收,如果没数据就卡住,但是我想触发EOFError,看被人解释是当管道中数据没有东西时就会抛出EOFError,但是我这里死活不抛出,就是卡住。 后来发现是close的问题,但是下面的代码我也加了close了, from multiprocessing import Process from multiproce...

auspark的专栏 2777

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Stream文件流模块以及pipe()进行大文件复制

Stream文件流模块原理 文件流的概念 Node中File System 模块并没有提供一个 copy的方法,但是可以通过读取文件和写入文件的方式实现; 把文件A的内容全部读入Buffer缓冲区,然后再从缓冲区写入文件B,该过程的执行流程图如下: 缺点: Buffer缓冲区限制在1GB,这样的操作对于小型的文本文件,没有多大问题,但是对于较大的文件,比如音频,视频文件,如果使用这种方法...

Calla_Lj的博客 3018

【Unix/Linux】unix-管道pipe()使用说明

pipe()是unix/linux中的系统调用用于构建管道。 管道即在命令行中表现为command1 | command2的对象。

太白断水客 1983

io.pipe会阻塞,而os.pipe()不会阻塞

一个有效的答案可能是 io.Pipe() 是错误的工具,因为 $REASONS 但我无法弄清楚那些 $REASONS 是因为根据文档,我正在尝试做的事情似乎完全合理。不是我上面使用的 io.Pipe(),而是 os.Pipe()(一个较低级别的调用,大致映射到 pipe(2) 在 POSIX 中)被使用。好吧,所以我猜 io.Pipe() 与 os.Pipe() 完全不同,并且可能不像 Unix 管道那样close() 不会为所有人关闭它。在使用子进程并通过管道读取标准输出时,我注意到了一些有趣的行为。

shelutai的博客 360
上一篇: RM9200中flash文件系统的移植
下一篇: MISRA 2004规则
张志龙
博客等级 码龄24年 412粉丝 131原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值