进程挂起,PIPE 被阻塞

Posted

技术标签:

【中文标题】进程挂起,PIPE 被阻塞【英文标题】:Process hangs and PIPE is blocked 【发布时间】:2013-05-10 21:00:09 【问题描述】:

我似乎陷入了僵局。我有 perl 脚本分叉并调用另一个 perl 脚本。并且该过程在某处挂起。

我正在运行程序: 达尔文内核版本 12.3.0:2013 年 1 月 6 日星期日 22:37:10 PST;根:xnu-2050.22.13~1/RELEASE_X86_64 x86_64

“lsof”有 4 个条目引用同一个 PIPE:

perl5.12 1414 根 1 管道 0x48937dc1254fe937 16384 ->0x48937dc1254fe727

perl5.12 1768 根 1 管道 0x48937dc1254fe937 16384 ->0x48937dc1254fe727

perl5.12 1759 根 1 管道 0x48937dc1254fe937 16384 ->0x48937dc1254fe727

perl5.12 1760 根 1 管道 0x48937dc1254fe937 16384 ->0x48937dc1254fe727

我怀疑这是挂起的原因。 我们是否有任何命令可以告诉我哪个进程读取/写入此 PIPE? 或任何进一步的信息将不胜感激。 提前致谢!

【问题讨论】:

好问题,但这里离题了。尝试 serverfault 或超级用户。 【参考方案1】:

我能想到两种可能的可能性:

    由于输出缓冲导致死锁。尝试在所有输出管道上启用自动刷新。如果两个进程使用管道进行双向通信,则很可能出现这种情况:它们各自写入内容并等待读取响应,但由于输出被缓冲,因此响应永远不会发送到管道。

    一个进程正在管道上等待 EOF,但它永远不会到来。如果管道是在父进程中创建的,然后被子进程继承,则需要确保所有进程都关闭管道的写端,这样读者才会读到EOF。

【讨论】:

感谢您的及时回复。我尝试在所有 fds (fd->autoflush;) 上为挂起的脚本启用自动刷新 (ps -ax)。但它没有帮助。我还确保所有的开口都关闭了。有没有办法知道哪个脚本可能正在读取或写入 PIPE?谢谢你。 我可以关闭特定进程的所有打开文件句柄吗?我没有 proc 文件系统 (/proc//fd)。 也许您可以使用dtruss 来查看每个进程在做什么。但我想你会发现他们都在read(),我不知道这会有多大帮助。【参考方案2】:

正如 Barmar 还解释的那样,当输出缓冲区填满时,子进程可能会卡住。在这种情况下,您会发现子进程卡在write() 函数调用中。

您必须在父进程中使用 Perl IO::Select 模块来继续从子进程读取输出缓冲区,如果子进程的输出大于缓冲区,则将其清空。

官方 Perl 文档位于 http://perldoc.perl.org/functions/sysread.html 解释:

sysread FILEHANDLE,SCALAR,LENGTH 尝试读取 LENGTH 个字节的数据 使用 read(2) 从指定的 FILEHANDLE 到变量 SCALAR。它 绕过缓冲 IO,因此将其与其他类型的读取、打印、 write、seek、tell 或 eof 可能会导致混淆,因为 perlio 或 stdio 层通常缓冲数据。

进一步查看系统活动我通常使用strace 命令,它很好地显示了每个进程如何读取和写入数据。

【讨论】:

以上是关于进程挂起,PIPE 被阻塞的主要内容,如果未能解决你的问题,请参考以下文章

进程的阻塞和挂起的区别

进程的阻塞和挂起的区别

高级IO,阻塞于非阻塞

linux内核阻塞IO

进程的挂起阻塞和睡眠

018_linux驱动之_阻塞和非阻塞