为何dup2在fork后调用失效,fork前调用正常?
管道、fork与dup代码差异的原因分析
核心问题:管道的读写端引用计数与进程阻塞逻辑
管道的关键特性是:只有当所有写端文件描述符都被关闭时,读端进程读取到EOF后才会终止;如果还有写端未关闭,读端会一直阻塞等待新数据。
无效代码的问题
父进程未释放管道写端引用
父进程在write后没有执行dup2(out, 1)恢复stdout,此时父进程的1号文件描述符(stdout)仍指向管道写端。fork后子进程继承了这个指向管道写端的stdout,虽然子进程自身通过dup2(out, 1)将stdout切回终端,但父进程的stdout依然持有管道写端的引用。grep进程持续阻塞
子进程启动的grep读取完管道内的"ola\nmundo\n"后,发现管道写端仍被父进程持有(未完全关闭),会一直阻塞等待新输入,不会退出。父进程卡在waitpid处等待子进程结束,最终导致整个程序无法正常终止;同时grep的输出因进程阻塞无法正常刷新到终端,表现为无输出。
有效代码的修复逻辑
父进程提前释放管道写端引用
fork前父进程执行dup2(out, 1)将stdout恢复为终端,此时父进程不再持有管道写端的任何引用(原管道写端的文件描述符被覆盖关闭)。grep进程正常退出
fork后子进程继承的stdout是终端,将stdin切换为管道读端后,grep读完数据发现所有管道写端已关闭,会正常处理匹配并退出。父进程通过waitpid等待子进程结束后,程序正常终止,grep的输出也能正常显示在终端。
内容的提问来源于stack exchange,提问作者ZmRR
相关产品推荐
相关产品推荐

