管道破裂不再终止程序?

时间:2020-03-06 14:26:35  来源:igfitidea点击:

当我们通过管道传输两个进程并在管道的"输出"处杀死一个进程时,第一个进程用于接收"管道中断"信号,该信号通常也会终止。例如。跑步

$> do_something_intensive | less

然后退出的习惯较少,可以使我们立即返回到SuSE8或者以前版本的响应shell。
当我今天尝试这样做时,do_something_密集型显然仍在运行,直到我手动将其杀死。似乎已经发生了某些变化(glib?shell?),使程序忽略了"断开的管道" ...

有人对此有暗示吗?如何恢复以前的行为?为什么更改了它(或者为什么它总是存在多种语义)?

编辑:进一步的测试(使用strace)显示生成了" SIGPIPE",但是程序没有被中断。一个简单的

#include <stdio.h>
int main() 
{
   while(1) printf("dumb test\n");
   exit(0);
}

会持续不断

--- SIGPIPE (Broken pipe) @ 0 (0) ---
write(1, "dumb test\ndumb test\ndumb test\ndu"..., 1024) = -1 EPIPE (Broken pipe)

当更少的人被杀死时。我可以确定在程序中编写一个信号处理程序并确保其终止,但是我更多的是在寻找一些环境变量或者shell选项,这些变量会强制程序在SIGPIPE上终止

再次编辑:这似乎是tcsh特有的问题(bash可以正确处理)并且依赖终端(Eterm 0.9.4)

解决方案

好吧,如果在读取器离开后尝试写入管道,则会生成SIGPIPE信号。该应用程序可以捕获此信号,但如果不捕获该信号,则该进程将被终止。

在调用过程尝试写入之前,不会生成SIGPIPE,因此,如果没有更多输出,则不会生成。

"做一些密集的事情"有没有改变?

正如Daniel提到的那样,SIGPIPE并不是一个神奇的"管道消失了"的信号,而是一个"不错的尝试,我们不能再读/写该管道"信号。

如果我们可以控制"密集工作",则可以对其进行更改以在旋转时写出一些"进度指示器"输出。这将及时提高SIGPIPE。

感谢建议,解决方案越来越近...

根据tcsh的联机帮助页,"非登录外壳程序从其父级继承终止行为。其他信号具有该外壳程序从其父级继承的值。"

这表明我的终端实际上​​是问题的根源...如果它忽略了SIGPIPE,则外壳程序本身也将忽略SIGPIPE ...

编辑:我有明确的确认,该问题仅与Eterm + tcsh有关,并在Eterm源代码中发现可疑的信号丢失(SIGPIPE,SIG_DFL)。我认为结案了。