java - 如何防止 SIGINT 信号杀死 Java 中的子进程
问题描述
我正在使用 Java exec 运行 bash 脚本,但是当我输入 CTRL+C 时,Java 进程和子进程都会退出,如何在 JVM 关闭后保持子进程运行?
String command = "ffmpeg -re -strict -2 -i video.mp4 -c:v copy -an -f rtp rtp://127.0.0.1:1234";
Utils.writeToFile("sub.sh", command);
new ProcessBuilder("parent.sh", "sub.sh").inheritIO()
.start().waitFor();
父.sh:
#!/bin/bash
trap '' SIGINT SIGTERM SIGQUIT SIGHUP SIGTSTP
nohup "$@" &
我已经在这里和这里阅读了类似问题的答案,例如,使用 nohup 在该脚本运行命令中启动父 bash 脚本,或使用陷阱命令来防止信号,在我的研究中,它适用于例如“tail -f somefile”,但是不适用于我的用例“ffmpeg -params”,请帮忙,谢谢。
解决方案
TL;博士
使用setsid
而不是nohup
在你的parent.sh
:
#!/bin/bash
setsid $@ &
第一个问题是当您的 Java 程序接收到一个SIGTERM
信号时(在 之后CTRL + C
),JVM 向SIGKILL
子进程发送一个信号,该信号不能被捕获、阻塞或忽略。因此,一旦您的parent.sh
进程收到SIGKILL
,它就会被传递给它的子进程,该子进程sub.sh
会停止该进程。
第二个问题是nohup "$@" &
你让你的sub.sh
子程序在后台运行,但它并没有完全脱离当前终端。nohup
基本上是忽略信号SIGHUP
。它正常执行进程(在后台),实际上并不提供守护进程。
代替nohup
,您可以使用setsid,它通过创建一个新会话来分离子进程sub.sh
,该会话将没有控制终端,因此不会接收到SIGKILL
信号。
另一种方法可能是使用disown
, like source $@ & disown
,但在这种情况下,它不会阻塞parent.sh
正在运行的当前终端。问题是,您将无法知道子进程何时完成。所以你需要做更多的工作来监控子进程ID。
进一步说明:
推荐阅读
- c - 我无法使用 getchar() 读取数字
- c# - 从不同的相对路径加载资源导致 500 错误 - 配置有什么问题?
- php - 验证时 Recaptcha 错误代码“连接失败”
- angular - 用户授予访问权限后,angular-ouath2-oidc 不重定向
- r - Plotly (r):下拉框中的值可以自动更改以反映数据框的更改吗?
- python - 无法修补 logging.Logger.info 在 celery 任务中调用
- typescript - 从数组中转移值的类型守卫
- npm - 为客户提供私人 npm
- sql - 如何在 SQL 中实现循环?
- unity3d - 以编程方式控制 Oculus Quest 相机直通模式