![PHP 调用时无法终止进程组](https://linux22.com/image/107797/PHP%20%E8%B0%83%E7%94%A8%E6%97%B6%E6%97%A0%E6%B3%95%E7%BB%88%E6%AD%A2%E8%BF%9B%E7%A8%8B%E7%BB%84.png)
我有一个生成两个僵尸的脚本。我可以通过 杀死该组kill -- -<parent-pid>
,但是当由 PHP 解释器调用时,这将不起作用,尽管手动杀死每个进程会起作用。
脚本是
#!/bin/bash
sleep 1d&
sleep 1d
PHP 文件只是调用它:
<?php
exec("./spawn")
?>
直接从外壳:
$ ./spawn&
[1] 19871
$ pstree -p 19871
spawn(19871)─┬─sleep(19872)
└─sleep(19873)
$ kill -- -19871
$ pstree -p 19871
[1]+ Terminated ./spawn
...并通过 PHP:
$ php -f zomby.php &
[1] 19935
$ pstree -p 19935
php(19935)───sh(19936)───spawn(19937)─┬─sleep(19938)
└─sleep(19939)
$ kill -- -19937
bash: kill: (-19937) - No matching process found
$ kill -- -19936
bash: kill: (-19936) - No matching process found
$ kill 19939 19938 19937
$ Terminated
[1]+ Fertig php -f zomby.php
只有杀死 PHP 父进程才有效:
$ php -f zomby.php &
[1] 20021
$ pstree -p 20021
php(20021)───sh(20022)───spawn(20023)─┬─sleep(20024)
└─sleep(20025)
$ kill -- -20021
$ pstree -p 20021
[1]+ Terminated php -f zomby.php
对此有什么想法吗?
答案1
kill
当给定的 PID < -1 时,该命令将其视为进程组 ID (PGID),而不是进程 ID。这记录在info kill
:
‘PID < -1’
The process group whose identifier is −PID.
如果我们再次以你的例子为例:
$ pstree -p 19935
php(19935)───sh(19936)───spawn(19937)─┬─sleep(19938)
└─sleep(19939)
PGID 是进程树最顶层父进程的 PID,在本例中为19935
。然而,您试图杀死属于 ID 和 进程组的进程19937
,19936
这两个进程实际上都不是进程组 ID。 PGID 是19935
。
您也许可以通过 更清楚地看到这一点ps
。如果我在我的系统上运行相同的命令:
$ php -f ./zombie.php &
[2] 12882
$ ps -o pid,ppid,pgid,command | grep -E '[P]GID|[1]2882'
PID PPID PGID COMMAND
12882 1133 12882 php -f ./zombie.php
12883 12882 12882 /bin/bash ./spawn
12884 12883 12882 sleep 1d
12885 12883 12882 sleep 1d
在上面的示例中,该组的 PGID 是12882
,所以如果我想杀死该组中的所有内容,我需要使用它。
当您直接从 shell 运行命令时,最顶层的父进程是 shell 脚本的 PID,因此您可以通过运行以下命令来终止其树中的所有进程kill -- -PID
:
$ ./spawn &
[3] 14213
terdon@tpad foo $ ps -o pid,ppid,pgid,command | grep -E '[P]GID|[1]4213'
PID PPID PGID COMMAND
14213 1133 14213 /bin/bash ./spawn
14214 14213 14213 sleep 1d
14215 14213 14213 sleep 1d
但那是因为 shell 脚本的 PID 是该组的 PGID。