- 练习 16:处理进程,
ps,kill- 这样做
- 你会看到什么
- 解释
- 附加题
练习 16:处理进程,ps,kill
原文:Exercise 16. Processes: working with proccesses, ps, kill
译者:飞龙
协议:CC BY-NC-SA 4.0
自豪地采用谷歌翻译
最简单的程序是硬盘上的文件,它包含中央处理器执行的指令。当你启动它的时候,它被复制到内存,控制权传递给它。被执行的程序称为进程。在例如 Linux 的多任务操作系统中,你可以启动程序的许多实例,因此可以从一个程序启动许多进程,所有程序将同时运行(执行)。
这是执行ls时发生的事情的概述:
你把 ls 和它的参数输入到你的终端模拟器,然后按 <ENTER>控制权现在传递给 BashBash在你的硬盘上查找 ls将自身派生到 Bash 克隆体,也就是将自己克隆到内存中的新位置成为 Bash 克隆体的父进程控制权传给了传递给 Bash 克隆体Bash 克隆体成为 Bash 的子进程保存 Bash 父进程的环境知道它是一个克隆体并且做出相应的反应使用 ls 覆盖自身控制权现在传递给 lsls为你打印一个目录列表或返回错误返回退出代码控制权现在传递给 BashBash将 ls 退出代码赋给 ? 变量等待你的输入你可以再次输入内容
一些进程不像ls那样交互,只是在后台静静地工作,就像ssh一样。进程有许多可能的状态,并且有许多操作,你可以通过信号机制对它们执行。
首先让我们谈论状态。如果你键入ps ax -forest,它将打印出所有进程,你会得到这样的东西(跳过一些与硬件有关的进程):
user1@vm1:/etc$ ps --forest axPID TTY STAT TIME COMMAND1 ? Ss 0:16 init [2]297 ? S<s 0:00 udevd --daemon392 ? S< 0:00 \_ udevd --daemon399 ? S< 0:00 \_ udevd --daemon691 ? Ss 0:00 /sbin/portmap703 ? Ss 0:00 /sbin/rpc.statd862 ? Sl 0:00 /usr/sbin/rsyslogd -c4886 ? Ss 0:00 /usr/sbin/atd971 ? Ss 0:00 /usr/sbin/acpid978 ? Ss 0:01 /usr/sbin/cron1177 ? Ss 0:00 /usr/sbin/sshd6671 ? Ss 0:00 \_ sshd: user1 [priv]6675 ? S 0:00 \_ sshd: user1@pts/06676 pts/0 Ss 0:00 \_ -bash7932 pts/0 R+ 0:00 \_ ps --forest ax1191 ? Ss 0:00 /usr/sbin/exim4 -bd -q30m1210 tty2 Ss+ 0:00 /sbin/getty 38400 tty21211 tty3 Ss+ 0:00 /sbin/getty 38400 tty31212 tty4 Ss+ 0:00 /sbin/getty 38400 tty41213 tty5 Ss+ 0:00 /sbin/getty 38400 tty51214 tty6 Ss+ 0:00 /sbin/getty 38400 tty66216 tty1 Ss+ 0:00 /sbin/getty 38400 tty1
让我们浏览这个列表:
PID - 进程 ID。每个进程都有与之相关联的唯一编号,用于唯一标识它。这意味着没有两个进程可以拥有相同的 PID。TTY - 与进程相关联的电传模拟器,允许进程与你交换信息。STAT - 当前进程状态。这将在下面详细描述。TIME - 这是在 CPU 上执行此进程的时间(以分钟为单位)。COMMAND - 这是带有参数的程序名称。请注意/usr/sbin/sshd是sshd: user1的父进程,而sshd: user1又是sshd: user1@pts/0的父进程,而sshd: user1@pts/0又是bash的父进程,而bash又是ps –forest ax的父进程。你需要更深入一些!
现在让我们讨论可能的进程状态。你可以参考man ps的 PROCESS STATE CODES。
| 状态 | 描述 |
|---|---|
| D | 不中断睡眠(通常为 IO)。进程繁忙或挂起,不响应信号,例如硬盘已经崩溃,读操作无法完成。 |
| R | 运行或可运行(在运行队列中)。进程正在执行中。 |
| S | 中断睡眠(等待事件完成)。例如,终端进程和 Bash 通常处于此状态,等待你键入某些内容。 |
| T | 停止,由任务控制信号或由于被追踪。 |
| W | 分页(从 2.6.xx 内核起无效,所以不用担心)。 |
| X | 死亡(不应该看到)。 |
| Z | 已停止(“僵尸”)进程,已终止,但未被父项收回。这种情况发生在错误终止的进程上。 |
| < | 高优先级(对其他用户不好) |
| N | 低优先级(对其他用户很好) |
| L | 将页面锁定到内存中(用于实时和自定义 IO) |
| s | 是会话领导。Linux 中的相关进程被视为一个单元,并具有共享会话 ID(SID)。如果进程 ID(PID)= 会话 ID(SID),则此进程将是会话领导。 |
| L | 是多线程的(使用 CLONE_THREAD,例如 NPTL pthreads) |
| + | 位于前台进程组。这样的处理器允许输入和输出到电传模拟器,tty。 |
现在让我们讨论,与所有这些进程沟通的方式。你可以通过发送信号来实现它。信号可能是一种鞭策进程方式,所以进程会听你的话,并做出你想要的行为。这是可能的进程的缩略列表,我从man kill的SIGNALS部分获得:
| 信号 | 编号 | 行为 | 描述 |
| 0 | 0 | N/A | 退出代码表示是否可以发送信号 |
| HUP | 1 | 退出 | 控制终端挂起或父进程死亡 |
| INT | 2 | 退出 | 来自键盘的中断 |
| QUIT | 3 | 内核 | 来自键盘的退出 |
| ILL | 4 | 内核 | 非法指令 |
| TRAP | 5 | 内核 | 跟踪/断点捕获 |
| ABRT | 6 | 内核 | 来自abort(3)的中止信号 |
| FPE | 8 | 内核 | 浮点异常 |
| KILL | 9 | 退出 | 不可捕获,不可忽视的杀死 |
| SEGV | 11 | 内核 | 内存引用无效 |
| PIPE | 13 | 退出 | 损坏的管道:写入没有读者的管道 |
| ALRM | 14 | 退出 | 来自alarm(2)的定时器信号 |
| TERM | 15 | 退出 | 终止进程 |
同样,不要因为不理解而害怕,因为现在你只需要了解HUP,TERM和KILL。甚至有一首关于KILL信号的歌曲 ,命名为《Kill dash nine》。另外,注意到abort(3)和alarm(2)了么?这意味着你可以通过键入man 3 abort和man 2 alarm来阅读相应的手册页。
现在,你将学习如何列出正在运行的进程并向其发送信号。
这样做
1: ps x2: ps a3: ps ax4: ps axue --forest5: dd if=/dev/zero of=~/test.img bs=1 count=$((1024*1024*1024)) &6: kill -s USR1 $!7: <ENTER>8: kill -s USR1 $!9: <ENTER>10: kill -s TERM $!11: <ENTER>
你会看到什么
user1@vm1:/etc$ ps xPID TTY STAT TIME COMMAND6675 ? S 0:00 sshd: user1@pts/06676 pts/0 Ss 0:00 -bash8193 pts/0 R+ 0:00 ps xuser1@vm1:/etc$ ps aPID TTY STAT TIME COMMAND1210 tty2 Ss+ 0:00 /sbin/getty 38400 tty21211 tty3 Ss+ 0:00 /sbin/getty 38400 tty31212 tty4 Ss+ 0:00 /sbin/getty 38400 tty41213 tty5 Ss+ 0:00 /sbin/getty 38400 tty51214 tty6 Ss+ 0:00 /sbin/getty 38400 tty66216 tty1 Ss+ 0:00 /sbin/getty 38400 tty16676 pts/0 Ss 0:00 -bash8194 pts/0 R+ 0:00 ps auser1@vm1:/etc$ ps axPID TTY STAT TIME COMMAND1 ? Ss 0:16 init [2]--- skipped --- skipped --- skipped ---691 ? Ss 0:00 /sbin/portmap703 ? Ss 0:00 /sbin/rpc.statd862 ? Sl 0:00 /usr/sbin/rsyslogd -c4886 ? Ss 0:00 /usr/sbin/atd971 ? Ss 0:00 /usr/sbin/acpid978 ? Ss 0:01 /usr/sbin/cron1177 ? Ss 0:00 /usr/sbin/sshd1191 ? Ss 0:00 /usr/sbin/exim4 -bd -q30m1210 tty2 Ss+ 0:00 /sbin/getty 38400 tty21211 tty3 Ss+ 0:00 /sbin/getty 38400 tty31212 tty4 Ss+ 0:00 /sbin/getty 38400 tty41213 tty5 Ss+ 0:00 /sbin/getty 38400 tty51214 tty6 Ss+ 0:00 /sbin/getty 38400 tty66216 tty1 Ss+ 0:00 /sbin/getty 38400 tty16671 ? Ss 0:00 sshd: user1 [priv]6675 ? S 0:00 sshd: user1@pts/06676 pts/0 Ss 0:00 -bash8198 pts/0 R+ 0:00 ps axuser1@vm1:/etc$ ps axue --forestUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND--- skipped --- skipped --- skipped ---root 1 0.0 0.0 8356 820 ? Ss Jun06 0:16 init [2]root 297 0.0 0.0 16976 1000 ? S<s Jun06 0:00 udevd --daemonroot 392 0.0 0.0 16872 840 ? S< Jun06 0:00 \_ udevd --daemonroot 399 0.0 0.0 16872 836 ? S< Jun06 0:00 \_ udevd --daemondaemon 691 0.0 0.0 8096 532 ? Ss Jun06 0:00 /sbin/portmapstatd 703 0.0 0.0 14384 868 ? Ss Jun06 0:00 /sbin/rpc.statdroot 862 0.0 0.1 54296 1664 ? Sl Jun06 0:00 /usr/sbin/rsyslogd -c4daemon 886 0.0 0.0 18716 436 ? Ss Jun06 0:00 /usr/sbin/atdroot 971 0.0 0.0 3920 644 ? Ss Jun06 0:00 /usr/sbin/acpidroot 978 0.0 0.0 22400 880 ? Ss Jun06 0:01 /usr/sbin/cronroot 1177 0.0 0.1 49176 1136 ? Ss Jun06 0:00 /usr/sbin/sshdroot 6671 0.0 0.3 70496 3284 ? Ss Jun26 0:00 \_ sshd: user1 [priv]user1 6675 0.0 0.1 70496 1584 ? S Jun26 0:00 \_ sshd: user1@pts/0user1 6676 0.0 0.6 23644 6536 pts/0 Ss Jun26 0:00 \_ -bash LANG=en_US.UTF-8 USER=user1 LOGNAME=user1 HOMuser1 8199 0.0 0.1 16312 1088 pts/0 R+ 17:07 0:00 \_ ps axue --forest TERM=screen-bce SHELL=/bin/bas101 1191 0.0 0.1 44148 1076 ? Ss Jun06 0:00 /usr/sbin/exim4 -bd -q30mroot 1210 0.0 0.0 5932 616 tty2 Ss+ Jun06 0:00 /sbin/getty 38400 tty2root 1211 0.0 0.0 5932 612 tty3 Ss+ Jun06 0:00 /sbin/getty 38400 tty3root 1212 0.0 0.0 5932 612 tty4 Ss+ Jun06 0:00 /sbin/getty 38400 tty4root 1213 0.0 0.0 5932 612 tty5 Ss+ Jun06 0:00 /sbin/getty 38400 tty5root 1214 0.0 0.0 5932 616 tty6 Ss+ Jun06 0:00 /sbin/getty 38400 tty6root 6216 0.0 0.0 5932 612 tty1 Ss+ Jun14 0:00 /sbin/getty 38400 tty1user1@vm1:/etc$ dd if=/dev/zero of=~/test.img bs=1 count=$((1024*1024*1024)) &[1] 8200user1@vm1:/etc$ kill -s USR1 $!user1@vm1:/etc$ 1455424+0 records in1455424+0 records out1455424 bytes (1.5 MB) copied, 1.76646 s, 824 kB/suser1@vm1:/etc$ kill -s USR1 $!user1@vm1:/etc$ 3263060+0 records in3263060+0 records out3263060 bytes (3.3 MB) copied, 3.94237 s, 828 kB/suser1@vm1:/etc$ kill -s TERM $!user1@vm1:/etc$[1]+ Terminated dd if=/dev/zero of=~/test.img bs=1 count=$((1024*1024*1024))user1@vm1:/etc$
解释
- 打印你拥有(启动)的进程。
- 仅打印与终端(
tty)相关的进程和你拥有(启动)的进程。 - 打印所有正在运行的进程。
- 以树形式打印所有正在运行的进程,并包含附加信息,例如可用的相关用户名和环境。请注意,此信息仅适用于你拥有(启动)的进程。为了查看所有进程的环境信息,请输入
sudo ps axue -forest。 - 开始创建一个零填充文件(填充为空字符,现在不要纠结),并通过在末尾指定
&发送到后台。 - 查询
dd的状态。 - 因为 bash 只能打印一些东西来回应你的输入,你需要按
<ENTER>(发出空指令)。 - 再次查询
dd的状态。 - 同样,你需要按
<ENTER>来查看输出。 - 向
dd发送终止信号,所以dd退出了。 - 为了看到它确实发生了,你需要再次按
<ENTER>键 。
附加题
- 阅读
man ps,man kill。 - 阅读进程的生命周期,并研究这张图片:进程的工作流。
- 打印并填写信号表。你可以使用 kernel.org 中的文档。
