You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何管道读端关闭时未触发SIGPIPE信号?

问题分析:为什么写入管道未触发SIGPIPE反而阻塞?

你遇到的问题核心在于父进程没有关闭管道的文件描述符,导致管道的读端并未完全关闭,因此不满足SIGPIPE的触发条件。

关键原理回顾

根据管道的行为规则:只有当管道的所有读端文件描述符都被关闭时,进程向管道写入才会触发SIGPIPE信号(默认会终止进程),同时write调用会返回EPIPE错误。

你的代码中的问题

在你的main函数中,创建完两个子进程后,父进程仍然持有两对管道的全部4个文件描述符:

  • ask_to_calc[0](管道读端)、ask_to_calc[1](管道写端)
  • calc_to_ask[0](管道读端)、calc_to_ask[1](管道写端)

当计算进程(calc_pid)退出时,它持有的ask_to_calc[0]会被内核回收,但父进程还拿着ask_to_calc[0]这个读端文件描述符!这意味着ask_to_calc管道的读端并没有完全关闭——系统中还有父进程持有它的读端。

这时候出题进程(ask_pid)向ask_to_calc管道写入数据时,因为管道还有读端存在(只是没有进程去读取数据),写入操作会进入阻塞状态(默认管道是阻塞模式),而不是触发SIGPIPE。

同时父进程在wait循环中等待子进程退出,出题进程阻塞在写入操作上无法退出,导致程序陷入阻塞,只输出calc terminated normally后就停住了。

解决方法:父进程关闭无用的管道文件描述符

父进程不需要使用这两对管道,所以在创建完两个子进程后,应该立即关闭所有管道的文件描述符,这样就能保证当子进程退出时,管道的对应端会被完全关闭。

修改main函数,在创建完两个子进程后添加以下代码:

// 父进程关闭所有管道文件描述符,不再持有管道的读写端
close(ask_to_calc[0]);
close(ask_to_calc[1]);
close(calc_to_ask[0]);
close(calc_to_ask[1]);

验证效果

修改后运行程序:

  1. 计算进程(calc_pid)会立即退出(因为你清空了calc_a_plus_b的代码)
  2. 此时ask_to_calc管道的所有读端都已关闭(父进程和计算进程都关闭了对应的fd)
  3. 出题进程(ask_pid)尝试向管道写入时,会触发SIGPIPE信号被终止
  4. 父进程会输出:
    calc terminated normally
    ask terminated due to signal 13
    

总结

管道的SIGPIPE触发条件依赖于全局范围内所有读端fd是否都关闭,父进程持有的管道fd很容易被忽略,这是管道编程中常见的坑。确保不需要使用管道的进程(比如这里的父进程)及时关闭管道fd,就能避免这类问题。

内容的提问来源于stack exchange,提问作者TsReaper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:39:26