Go标准库os/exec中closeAfterStart的作用及StdinPipe关闭逻辑疑问
为什么
StdinPipe关联的reader会在Start调用后立即关闭 StdinPipe的底层实现基于匿名管道,核心逻辑是:
- 调用
StdinPipe时,exec包内部会创建一组io.Pipe管道对:调用侧拿到的是可写入的*PipeWriter,管道的读端会被预先绑定到子进程的标准输入文件描述符 - 当调用
Start启动子进程时,操作系统会把这个管道读端的文件描述符复制到子进程的文件描述符表中,此时父进程侧持有的管道读端已经没有任何实际作用 - 按照Unix管道的设计规则,只有所有关联的写端都被关闭时,读端才会返回EOF信号。如果父进程不主动关闭这个多余的读端,就算调用侧已经关闭了拿到的
StdinPipe写端,管道的读端引用计数依然不为0,子进程会永远卡在读取标准输入的逻辑上,无法正常退出 - 因此在子进程启动后立即关闭父进程侧持有的管道读端,是保证管道IO逻辑正常运行的必要操作
closeAfterStart数组的设计用途 closeAfterStart是exec.Cmd结构体中专门用来统一管理临时资源的集合,核心作用是收纳所有父进程仅在子进程启动前需要持有、子进程启动完成后就不再需要的可关闭资源,除了上面提到的StdinPipe对应管道读端,它还会收纳以下资源:
StdoutPipe、StderrPipe对应的管道写端:和StdinPipe逻辑相反,这两类管道的写端会绑定到子进程的标准输出/标准错误输出,子进程启动后父进程持有的写端必须关闭,否则子进程退出后,调用侧读取输出时永远收不到EOF信号- 其他创建子进程过程中父进程临时打开、仅需要传递给子进程的文件描述符资源
统一放到closeAfterStart中管理的优势是避免分散处理带来的资源泄漏问题,Start逻辑执行完毕后只需要遍历数组统一关闭所有资源即可,不需要为不同类型的资源单独编写关闭逻辑。
内容的提问来源于stack exchange,提问作者user3803241
相关产品推荐
相关产品推荐

