自定义“垃圾收集器”来手动关闭程序

自定义“垃圾收集器”来手动关闭程序

我运行的是 Ubuntu 16.04

我有这个进程 X 从多个 tty 运行。我使用 screen 命令从其他伪终端运行它,它也从 crontab 运行。

该程序是从 python 脚本启动的,而 python 脚本是从 bash 脚本启动的。

有时,python 脚本会出现一个我无法捕获的异常,并且它会使该进程 X 继续运行。

我想在 bash 脚本末尾终止此进程 X,但避免终止从其他终端运行的其他 X 进程。

我想过使用 pgrep 来处理 X,它与使用 -t 参数的其他终端无关,但我无法理解文档中的语法。

答案1

为Python代码启动一个新的进程组(使用setsid实用程序)以及它启动的任何其他进程(包括应用程序本身),因此您可以根据需要杀死整个进程组。

您可以使用以下构造来执行此操作:

exec 3>&1
pgid=$(exec setsid bash -c 'echo $$; exec >&3-; exec COMMAND...')

哪里COMMAND...是您通常启动的命令及其参数。请注意,它位于单引号内,并且要运行的命令必须可作为字符串进行计算(而不是普通的 shell 表达式)。

第一个重定向3>&1将标准输出描述符复制到描述符 3。重定向将>&3-描述符 3 移动到标准输出。

执行, 并计算写入标准输出的数据$(...)...上面,我们将标准输出读入 shell 变量中pgid

子 shell ( ...) 替换为setsid实用程序,它在新会话(进程组)中执行其参数。在这里,它执行bash,打印出当前进程 PID( $$),将原始标准输出从描述符 3 移回,并替换自身/执行所需的COMMAND...

shell 将在运行期间执行该行,并且只有在自身退出COMMAND...后才会前进到下一行。COMMAND...

如果COMMAND...虚假进程仍在运行,并且您想杀死它们,您所需要做的就是运行

kill -SIGNAL -$pgid

问题是发送哪个信号。KILL会立即杀死进程组中剩余的进程,因此这是最简单的选择。但是,如果进程表现良好,您应该能够通过向他们发送信号来让他们退出TERM。当然,有时进程可能会处于不稳定状态,因此它们不会做出反应TERM并且确实需要进行KILL编辑。为了解决这个问题,您可以使用一个小循环,并ps查看是否还有剩余进程:

retries=50
while ((1)); do

    # Processes left?
    left=$(ps -o pid= -s $pgrp)
    [ -n "$left" ] || break

    # Ask them to terminate.
    kill -TERM $left

    # Wait 0.1 seconds.
    sleep .1

    # Decrement the retry counter.
    ((--retries > 0)) || break
done

# If there are any processes left in the group,
# send them a KILL signal.
left=$(ps -o pid= -s $pgrp)
[ -n "$left" ] && kill -KILL $left

请注意,50 次重试(每次重试 0.1 秒)意味着在发送终止信号之前最多仅等待 5 秒。这可能不是一个合适的值,具体取决于应用程序及其运行的硬件类型。例如,如果机器是笔记本电脑,并且应用程序保存一些历史记录或登录到多个文件中,并且驱动器恰好在退出点休眠,那么我会将延迟增加到大约 15 到 30 秒。

相关内容