第十章:进程

现代操作系统通常是多任务处理的,这意味着它们通过快速从一个执行程序切换到另一个程序,创造了一种同时做多件事的错觉。Linux内核通过使用进程(processes)来管理这一点。进程是Linux如何组织在CPU上等待轮到它们的不同程序的。

有时计算机会变得迟钝,或者应用程序会停止响应。在本章中,我们将介绍命令行上可用的一些工具,这些工具让我们检查程序正在做什么,以及如何终止行为异常的进程。

本章将介绍以下命令:

第十章:进程进程是如何工作的查看进程使用 top 动态查看进程控制进程中断进程将进程置于后台将进程带回前台停止(暂停)一个进程更改线程优先级信号使用 kill 向进程发送信号防止进程挂起使用 killall 向多个进程发送信号关闭系统更多与进程相关的命令总结

进程是如何工作的

当系统启动时,内核会启动一些自己的活动作为进程,并启动一个名为 init 的程序。 init 反过来启动 systemdsystemd 启动所有系统服务。在较旧的Linux发行版中, init 运行一系列名为 init scripts 的shell脚本(位于 /etc 中)来执行类似的功能。许多系统服务都是作为守护程序(daemon programs)实现的,这些程序只是坐在后台,在没有任何用户界面的情况下完成自己的工作。因此,即使我们没有登录,系统也至少有点忙于执行日常工作。

一个程序可以启动其他程序的事实在进程方案中表示为产生子进程(child process)的父进程(parent process)。

内核维护每个进程的信息,以帮助保持事物的有序性。例如,每个进程都被分配了一个称为进程ID(process ID ,PID)的数字。PID按升序分配, init 总是得到PID 1。内核还跟踪分配给每个进程的内存,以及进程恢复执行的准备情况。与文件一样,进程也有所有者和用户ID、有效(effective)用户ID等。

查看进程

查看进程(有几个)最常用的工具是 ps 命令。 ps 程序有很多选项,但最简单的形式是这样使用的:

此示例中的结果列出了两个进程,进程5198和进程10129,它们分别是 bashps 。正如我们所看到的,默认情况下, ps 不会向我们显示太多,只显示与当前终端会话相关的进程。要了解更多,我们需要添加一些选项,但在这样做之前,让我们看看 ps 生成的其他字段。

正如我们所看到的,这两个过程都没有让计算机工作得很努力。

如果我们添加一个选项,我们可以更全面地了解系统正在做什么。

添加 x 选项(注意没有前导破折号)告诉 ps 显示我们的所有进程,无论它们由哪个终端控制(如果有的话)。TTY列中的 ? 表示没有控制终端。使用此选项,我们可以看到我们拥有的每个进程的列表。

由于系统正在运行许多进程, ps 会生成一个长列表。为了便于查看,将 ps 的输出转换为 less 通常是有帮助的。一些选项组合也会产生长行(long line)输出,因此最大化终端模拟器窗口可能也是一个好主意。

输出中添加了一个名为 STAT 的新列。 STAT 是 "state"(状态) 的缩写,显示流程的当前状态,如下表所示:

状态含义
RRunning。这意味着进程正在运行或准备运行。
SSleeping。进程未运行;相反,它正在等待一个事件,比如击键或网络数据包。
D不间断的(Uninterruptible)睡眠。进程正在等待磁盘驱动器等I/O。
TStopped。已指示停止该进程。本章稍后将对此进行更多介绍。
Z已失效或“僵尸”(zombie)进程。这是一个已终止但尚未被其父进程清理的子进程。
<高优先级的进程。可以赋予进程更多的重要性,让它在CPU上有更多的时间。进程的这种特性被称为 niceness 。具有高优先级的进程被认为不太好,因为它占用了更多的CPU时间,这给其他人留下了更少的时间。
N低优先级进程。低优先级的进程(“nice”进程)只有在其他优先级较高的进程得到服务后,才会获得处理器时间。

进程状态后面可能跟有其他字符。这些表明了各种奇特的过程特征。有关更多详细信息,请参阅 ps 手册页。

另一组流行的选项是 aux (没有前导破折号)。这给了我们更多的信息。

这组选项显示属于每个用户的进程。使用不带前导破折号的选项会调用具有“BSD风格”行为的命令。 ps 的Linux版本可以模拟在几个不同的Unix实现中发现的 ps 程序的行为。最流行的BSD选项如下表所示:

选项功能
x列出我们正在运行的进程
ax列出所有运行中的进程
w包括完整命令名称
u详细列表

使用 aux 选项,我们得到了下表中所示的附加列:

标题含义
USER用户ID。进程的所有者。
%CPUCPU使用率。
%MEM内存使用率。
VSZ虚拟内存大小。
RSSResident set size。这是进程正在使用的物理内存(RAM)量,单位为千字节。
START进程开始的时间。对于超过24小时的值,使用日期。
TIME进程所消耗的CPU时间。

还可以通过将PID作为命令参数来生成单个进程的详细快照,如下例所示。

使用 top 动态查看进程

虽然 ps 命令可以揭示机器正在做什么,但它只提供执行 ps 命令时机器状态的快照。为了查看机器活动的更动态视图,我们使用 top 命令:

top 程序显示按进程活动顺序列出的系统流程的连续更新(默认情况下,每三秒一次)显示。 top 这个名字来自这样一个事实,即 top 程序用于查看系统上的“top”进程。 top 显示由两部分组成:显示于顶部的系统摘要,后面是按CPU活动排序的进程表:

系统摘要包含了很多好东西。以下是一个概述:

字段含义
1top程序的名字
 14:59:20当前时间
 up 6:30这被称为 uptime 。这是自上次启动机器以来的时间量。
在这个例子中,系统已经运行了六个半小时。
 2 users当前有两个用户登录了
 load average:load average ,平均负载,是指等待运行的进程数量,即处于可运行状态并共享CPU的进程数量。
显示了三个值,每个值对应不同的时间段。
- 第一个是最后60秒的平均值:
- 第二个是前5分钟的平均值;
- 最后是前15分钟的平均值。
值小于1.0表示机器不忙。
2Tasks:这总结了进程的数量及其各种进程状态。
3Cpu(s):此行描述了CPU正在执行的活动的特征。
 0.7%us0.7%的CPU用于 user processes 。这些进程在内核之外。
 1.0%sy1.0%的CPU用于system (内核)进程。
 0.0%ni0.0%的CPU被“nice”(低优先级)进程使用。
 98.3%id98.3%的CPU处于空闲状态(idle)。
 0.0%wa0.0%的CPU正在等待(waiting)I/O。
4Mem:这显示了物理RAM的使用情况。
5Swap:这显示了交换空间(虚拟内存)的使用情况。

top 程序接受许多键盘命令。最有趣的两个是 h ,它显示程序的帮助屏幕;以及 q ,它退出 top

两种主要的桌面环境都提供了显示类似于 top 的信息的图形应用程序(与Windows中的任务管理器的工作方式大致相同),但 top 比图形版本更好,因为它更快,消耗的系统资源更少。毕竟,我们的系统监控程序不应该是我们试图跟踪的系统减速的根源。

控制进程

现在我们可以查看和监控进程了,让我们对它们进行一些控制。在我们的实验中,我们将使用一个名为 xlogo 的小程序作为我们的豚鼠。 xlogo 程序是X Window系统(使我们显示器上的图形过时而有利于Wayland的底层引擎)提供的示例程序,它只是显示一个包含X徽标的可调整大小的窗口。首先,我们将了解我们的测试对象。

输入命令后,屏幕上的某个地方应该会出现一个包含徽标的小窗口。在某些系统上, xlogo 可能会打印警告消息,但可以安全地忽略它。

提示:如果您的系统不包含 xlogo 程序,请尝试使用 geditkwrite

我们可以通过调整窗口大小来验证 xlogo 是否正在运行。如果徽标以新尺寸重新绘制,则程序正在运行。

注意我们的shell提示符没有返回吗?这是因为shell正在等待程序完成,就像我们迄今为止使用的所有其他程序一样。如果我们关闭 xlogo 窗口,提示将返回。

Figure3_Thexlogoprogram

中断进程

让我们观察一下再次运行 xlogo 时会发生什么。首先,输入 xlogo 命令并验证程序是否正在运行。接下来,返回终端窗口并按 Ctrl - c

在终端中,按 Ctrl - c 会中断程序。这意味着我们礼貌地要求程序终止。按下 Ctrl - c 后,xlogo 窗口关闭,shell提示符返回。

使用此技术可以中断许多(但不是全部)命令行程序。

将进程置于后台

假设我们想在不终止 xlogo 程序的情况下恢复shell提示符。我们可以通过将程序置于后台,background ,来实现这一点。将终端视为具有 foreground (具有在表面上可见的内容,如shell提示)和 backgrand (具有隐藏在表面后面的内容)。要启动一个程序并将其立即放置在后台,我们可以在命令后面加上与号(ampersand,&)字符:

输入命令后, xlogo 窗口出现,shell提示符返回,但也打印了一些有趣的数字。此消息是名为作业控制的shell功能的一部分。通过此消息,shell告诉我们我们已经启动了作业编号1([1]),并且它的PID为28236。如果我们运行 ps ,我们可以看到我们的进程:

shell的作业控制工具还为我们提供了一种列出从终端启动的作业的方法。使用 jobs 命令,我们可以看到以下列表:

结果显示,我们有一个编号为1的作业正在运行,命令是 xlogo &

请注意,我们可以使用此快捷方式在后台放置多个命令,如下所示:

将进程带回前台

后台进程不受终端键盘输入的影响,包括任何用 Ctrl - c 中断它的尝试。要将进程返回到前台,请按以下方式使用 fg 命令:

fg 命令后面跟着一个百分号和作业编号(称为 jobspec)就可以了。如果我们只有一个后台作业,则jobspec是可选的。此时要终止 xlogo ,请按 Ctrl - c

停止(暂停)一个进程

有时我们想停止(stop)一个进程而不终止(terminating)它。这通常是为了允许前台进程移动到后台。要停止前台进程并将其置于后台,请按 Ctrl - z 。让我们试试。在命令提示符下,键入 xlogo ,按 Enter 键,然后按 Ctrl - z

停止 xlogo 后,我们可以通过尝试调整 xlogo 窗口的大小来验证程序是否已停止。我们会看到它看起来已经死了。我们可以使用 fg 命令在前台继续执行程序,也可以使用 bg 命令在后台继续执行程序:

fg 命令一样,如果只有一个作业,jobspec 是可选的。

如果我们从命令行启动一个图形程序,但忘记通过在后面附加 & 将其放置在后台,那么将进程从前台移动到后台会很方便。

为什么我们要从命令行启动图形程序?有两个原因。

更改线程优先级

正如我们在 ps 命令的输出(以及 top )中看到的,有一个名为 niceness 的进程属性,它指的是赋予进程的调度优先级。在某些情况下,例如在视频转码或执行基于CPU的光线跟踪(ray tracing)时,我们可能希望给进程更高的优先级(更不美观),或者如果我们希望进程使用更少的CPU时间,我们可以给它更美观(niceness)。niceness可以通过 nicerenice 命令进行调整。重要的是要记住,只有超级用户可以提高进程的优先级,而普通用户只能降低他们拥有的进程的优先级。

nice 命令以指定的niceness启动一个进程。良好度调整从-20(最有利,favorable,但最不nice)到19(最不利,但最nice)表示,默认值为零(无调整)。让我们看看这是如何工作的。想象一下,我们有一个名为 cpu-hog 的程序,我们想以比正常20更低的优先级运行。我们可以按如下方式启动 nice 程序:

同样,如果我们有一个名为 must-run-fast 的程序需要被赋予更高的CPU优先级,我们(作为超级用户)可以这样做:

很少有必要以更高的优先级运行命令,这样做可能会使基本系统进程缺少所需的CPU时间,因此要小心。

renice 命令调整正在运行的进程的优先级。例如,如果我们启动了 cpu-hug 程序,并希望在事后增加其友好性(niceness),我们可以这样做:

首先,我们运行 ps 来确定正在运行的 cpu-hug 程序的进程id,然后是具有所需nicess级别和进程id的 renice 命令。nicess级别19(最大值)很有用,因为它使进程只在没有其他等待的情况下使用CPU周期。

信号

Signals——信号

kill 命令用于“杀死”进程。这允许我们终止(terminate)需要终止的(need killing)程序(即某种暂停或终止)。这里有一个例子:

我们首先在后台启动 xlogo 。shell打印后台进程的 jobspecPID 。接下来,我们使用 kill 命令并指定要终止的进程的PID。我们还可以使用jobspec(例如%1)而不是PID指定进程。

虽然这一切都很简单,但还有更多。 kill 命令并不完全(excatly)“杀死”进程:相反,它向进程发送信号(signals)。信号是操作系统与程序通信的几种方式之一。我们已经看到了使用 Ctrl-cCtrl-z 时的信号。当终端收到其中一个按键时,它会向前台的程序发送信号。在 Ctrl-c 的情况下,会发送一个名为 INT(interrupt,中断)的信号;使用 Ctrl-z 发送称为 TSTP (terminal stop,终端停止)的信号。反过来,程序会“监听”(listen)信号,并在收到信号时对其采取行动。程序可以监听信号并对其采取行动的事实允许程序在收到终止信号时执行诸如保存正在进行的工作等操作。

使用 kill 向进程发送信号

kill 命令用于向程序发送信号。它最常见的语法如下:

kill [-signal] PID ...

如果命令行上没有指定信号,则默认情况下会发送 TERM(终止)信号。 kill 命令最常用于发送以下信号:

号码名称含义
1HUPHangup,挂起。
这是旧时代的遗迹,当时终端通过电话线和调制解调器连接到远程计算机。该信号用于向程序指示控制终端已“挂起”。此信号的效果可以通过关闭终端会话来演示。终端上运行的前台程序将收到信号并终止。
许多守护程序也使用此信号来重新初始化。这意味着当守护进程收到此信号时,它将重新启动并重新读取其配置文件。Apache web服务器就是这样使用 HUP 信号的守护进程的一个例子。
通过使用下面讨论的 nohup 命令启动进程,可以使其对 HUP 信号免疫。
2INTInterrupt,中断。
执行与从终端发送的 Ctrl-c 相同的功能。它通常会终止一个程序。
9KILLKill,杀掉。
这个信号很特别。尽管程序可能会选择以不同的方式处理发送给它们的信号,包括同时忽略它们,但 KILL 信号实际上从未发送到目标程序。相反,内核会立即终止进程。当一个进程以这种方式终止时,它没有机会在自身之后“清理”或保存其工作。因此,当其他终止信号失败时,应仅将 KILL 信号用作最后手段
15TERMTerminate,终止。
这是 kill 命令发送的默认信号。如果一个程序仍然”活跃“(alive)到足以接收信号,它将终止。
18CONTContinue,继续。
对于收到STOP或TSTP信号而停止的进程,收到此信号后将恢复运行。此信号由 bgfg 命令发送。
19STOPStop,停止。
此信号导致进程暂停而不终止。与 KILL 信号一样,它不会发送到目标进程,因此不能被忽略。
20TSTPTerminal stop,终端停止。
这是按下 Ctrl-z 时终端发送的信号。与STOP信号不同,TSTP信号由程序接收,但程序可以选择忽略它。

让我们试试 kill 命令:

在这个例子中,我们在后台启动 xlogo 程序,然后使用 kell 命令向其发送 HUP 信号。 xlogo 程序终止,shell指示后台进程已收到挂断信号。在消息出现之前,我们可能需要按几次 Enter 键。请注意,信号可以通过数字或名称指定,包括前缀为字母 SIG 的名称。

重复上述示例,并尝试其他信号。记住,我们也可以使用 jobspec 代替 PID

进程和文件一样,都有所有者,您必须是进程的所有者(或超级用户)才能使用 kill 向其发送信号。

除了上述最常用于杀死的信号列表外,还有下表中列出的系统经常使用的其他信号。

号码名称含义
3QUITQuit,退出。
11SEGVSegmentation violation,分段违规。
如果程序非法使用内存,即如果它试图在不允许写入的地方写入,则会发送此信号。
28WINCHWindow change,窗口更改。
这是当窗口大小改变时系统发送的信号。一些程序,如 topless ,会通过重新绘制自身以适应新的窗口尺寸来响应此信号。

对于好奇的人来说,可以使用以下命令显示完整的信号列表:

防止进程挂起

proof —— 防...的。

正如我们所讨论的,上面许多命令行程序将通过在其控制终端“挂起”(即关闭或断开连接)时终止来响应 HUP 信号。为了防止这种行为,我们可以使用 nohup 命令启动程序。这里有一个例子。

如果我们再次启动 xlogo 程序,然后关闭终端窗口,xlogo 将终止,因为当其控制终端关闭时,它会收到 HUP 信号。为了防止这种情况,我们可以使用 nohup 命令启动 xlogo ,如下所示:

现在,当我们关闭终端窗口时,xlogo将继续运行。

使用 killall 向多个进程发送信号

还可以使用 killall 命令向与指定程序或用户名匹配的多个进程发送信号。语法如下:

killall [-u user] [-signal] name ...

为了演示,我们将启动 xlogo 程序的几个实例,然后终止它们。

记住,与 kill 一样,我们必须拥有超级用户权限才能向不属于我们的进程发送信号。

关闭系统

关闭系统的过程包括有序终止系统上的所有进程,以及在系统断电前执行一些重要的日常工作(如同步所有已挂载的文件系统)。有四个命令可以执行此功能。它们是 haltpoweroffrebootshutdown 。前三个非常不言自明,通常在没有任何命令行选项的情况下使用。这里有一个例子:

shutdown 命令更有趣一些。通过它,我们可以指定要执行的操作(halt,停止、powerdown,断电或reboot,重新启动),并为关机事件提供时间延迟。最常用的方法是这样停止(halt)系统:

或者像以下方式重启系统:

延迟可以通过多种方式指定。有关详细信息,请参阅关机手册页。一旦执行了关机命令,就会向所有登录用户“广播”(broadcast)一条消息,警告他们即将发生的事件。

更多与进程相关的命令

由于监控进程是一项重要的系统管理任务,因此有很多命令可供使用。下表列出了一些可供使用的命令:

命令介绍
pstree输出以树状模式排列的进程列表,显示进程之间的父子关系。
vmstat输出系统资源使用情况的快照,包括内存、交换和磁盘I/O。
要查看连续显示,请按照带有时间延迟(以秒为单位)的命令进行更新。这里有一个例子:vmstat 5 。用 Ctrl-c 终止输出。
xload一种图形程序,绘制显示系统负载随时间变化的图形。
tload类似于xload程序,但在终端中绘制图形。用 Ctrl-c 终止输出。

总结

大多数现代系统都具有管理多个进程的机制。Linux为此提供了一套丰富的工具。鉴于Linux是世界上部署最多的服务器操作系统,这很有意义。然而,与其他一些系统不同,Linux主要依赖命令行工具进行进程管理。尽管Linux有图形化处理工具,但命令行工具因其速度快、占用空间小而备受青睐。虽然GUI工具看起来很漂亮,但它们本身通常会产生大量系统负载,这在一定程度上违背了目的。