我正在关注一个程序“主程序”,它管理一组并发运行的子进程“从程序”。子进程根据需要启动和终止。其中许多子流程都使用启动脚本。
输出pstree
看起来像这样(摘录,主站是用Java实现的,两个从站通过脚本启动):
systemd───java─┬─sh───slave
├─slave
└─sh───slave
以前,启动脚本将从站的输出重定向到日志文件。决定主设备也应该处理从设备的输出。通过添加缓冲读取器来扩展主设备的实现,如下所示:
process = Runtime.getRuntime().exec(cmd);
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
while (null != (line = br.readLine())) {
// handle slave output here
}
然后,系统对被SIGTERM
主人杀死(发送)但实际上仍在运行的奴隶产生了严重的问题。我注意到这件事发生了仅有的与满足两个标准的奴隶:
- 他们使用了启动脚本
- 他们很少写入标准输出
由于主设备没有杀死从设备,而只是杀死了它的直接父级(shell 解释器),因此从设备现在由 init 所有。就我而言,systemd 似乎是默认的收割者。pstree
看起来像这样:
systemd─┬─java───sh───slave
└─slave
从功能上讲,我通过明确地解决了这个问题杀死奴隶的全家。但我仍然想知道:
为什么 systemd 只有在写入标准输出(或错误)并且标准输出之前已被另一个进程读取时才会杀死孤立的子进程?
这个问题其实相当冗长。根据要求,我可以提供一个最小的代码示例来重现所描述的行为。
答案1
这可能不是 systemd 做的。
相反,当进程尝试写入读取端已关闭的管道时,该进程会被 SIGPIPE 终止——这符合“标准输出先前已被另一个进程读取”的描述。