为什么我无法在 Linux 上终止这个进程?

为什么我无法在 Linux 上终止这个进程?

问题

我想终止一个名为 raspivid 的进程(使用 Raspberry Pi 相机录制视频的程序),但我无法……

我是这样称呼它的:

#!/bin/bash

#Start recording...
raspivid -w 800 -h 600 -t 15000 -o $1 -v -n -rot 270 >> /home/pi/log/camera_output.txt 2>&1 &

#Waiting the video to be complete
sleep 16

#Killing child process
sudo kill -9 $!

#Killing parent process
sudo kill -9 $$

如果我搜索这个过程,它仍然在那里:

pi@raspberrypi ~ $ ps -ef | grep raspivid
root      7238     7234  0 21:53 ?        00:00:00 [raspivid]
pi       17096 14925  0 22:05 pts/0    00:00:00 grep --color=auto raspivid

如果我尝试杀死它,它不会死。相反,它会将父 PID 更改为 1:

pi@raspberrypi ~ $ sudo killall raspivid
pi@raspberrypi ~ $ ps -ef | grep raspivid
root      7238     1  0 21:53 ?        00:00:00 [raspivid]
pi       17196 14925  0 22:05 pts/0    00:00:00 grep --color=auto raspivid
pi@raspberrypi ~ $ sudo killall raspivid

观察结果:

  1. 通话正常进行一段时间(2 小时左右),然后就开始挂断。
  2. 只有物理关闭电源才能解决问题。我无法通过终端重新启动(它也挂了)

我的问题:

  1. 为什么Linux将父PID指定为1?
  2. 为什么进程不能被杀死?(我也试过sudo kill -9 7238

答案1

问题

你的脚本可能正在创建僵尸因为你的kill -9命令;正如建议的那样jjlin 回答在没有强制的情况下突然终止某些进程永远不是一个好的做法。

我们可以从中man bash读到:

标记为 <defunct> 的进程是死进程(所谓的“僵尸“)剩下的因为他们的父母没有妥善销毁它们. 这些过程将被 init(8) 销毁如果父进程退出。

答案#1:流程在里面PID 1为此,Linux 为它们分配了 PID 为 1 的父进程(因为它将它们分配给在里面)。

答案#2:它们无法被杀死简单地因为他们只是死的... 如果他们的父母init可能就足以等待一段时间了。

要从系统中移除僵尸进程,可以使用 kill 命令手动向父进程发送 SIGCHLD 信号。如果父进程仍然拒绝收割僵尸进程,下一步就是移除父进程。当进程失去父进程时,init 将成为其新的父进程。Init 会定期执行 wait 系统调用来收割以 init 为父进程的任何僵尸进程。[1]

万一有一天这个想法出现:以 root 权限进行#kill -9 init处理的软件相当于物理上将计算机从电网中拔出。[:-)]

然而僵尸进程ps可以通过命令输出中的“Z”来识别统计列。您可以使用以下行轻松识别它们

ps -aux | grep Z

一些参考资料Linux 僵尸世界

答案2

回答问题1:

当一个进程产生子进程时,每个子进程都有自己的 PID。每个子进程的 PPID(父进程的 id)是其父进程的 PID。如果父进程死亡,则子进程将变为孤儿进程。孤儿进程将由 PID 为 1 的系统 init 进程自动接收。

答案3

该程序可能打开了摄像头设备,通过强行关闭它,您没有让它正确清理,所以现在它卡住了。

一些观察:

  • 除非您知道自己在做什么,否则通常不要以 -9 开头来终止程序。只需正常终止(不带任何选项)即可。
  • 您的脚本中根本不需要执行任何终止操作。您已经将-t 15000视频的长度传递给程序,因此第一次终止操作应该是不必要的。第二次终止操作也是不必要的,因为当 shell 到达脚本末尾时,它将自行退出。如果程序没有自行退出(应该如此),那么您就遇到了其他问题。

答案4

这是我清理僵尸进程的一些技巧。我需要它,因为一个包的升级脚本一直在等待 killall -pw,但该进程是僵尸进程,因为 gnome-session 没有对其执行“waitpid”。所以我手动做了:

gdb
(gdb) attach <zombie parent PID>
(gdb) call waitpid( <zombie PID>, 0, 0)
(gdb) detach

就这样!僵尸进程被清理了!

相关内容