For the complete documentation index, see llms.txt. This page is also available as Markdown.

16.4 进程与守护进程

进程与守护进程概述

FreeBSD 是一个多任务操作系统。任何时刻运行的程序均称为进程。每个运行的命令至少启动一个新进程,此外还有许多由 FreeBSD 运行的系统进程。

每个进程都由一个称为进程 ID(PID)的数字唯一标识。与文件类似,每个进程都有一个属主和组,属主和组权限用于确定进程可以打开哪些文件和设备。大多数进程还有一个启动它们的父进程。例如,shell 是一个进程,在 shell 中启动的任何命令都是以 shell 为父进程的进程。例外是特殊进程 init(8),其始终是系统启动时的首个进程,并且始终具有 PID 1。在 FreeBSD 中,所有进程都是以某个账户的名义启动的。

Port sysutils/htop 能够直观地呈现这一点(注意 △USER 这列):

$ htop
  PID△USER       PRI  NI  VIRT   RES S   CPU% MEM%   TIME+  Command
    1 root        20   0 12724  1324 S    0.0  0.0  0:00.08 /sbin/init
  216 root        20   0 36172  7308 S    0.0  0.1  0:00.77 ├─ /usr/local/bin/vmtoolsd -c /usr/local/share/vmware-tools/to
  400 root        48   0 14188  2684 S    0.0  0.0  0:00.00 ├─ dhclient: system.syslog
  403 root         4   0 14188  2760 S    0.0  0.0  0:00.00 ├─ dhclient: em0 [priv]
  481 _dhcp       20   0 14192  2808 S    0.0  0.0  0:00.01 ├─ dhclient: em0
  596 root        20   0 15444  4204 S    0.0  0.1  0:00.05 ├─ /sbin/devd
  800 root        20   0 13904  2792 S    0.0  0.0  0:00.02 ├─ /usr/sbin/syslogd -s
  867 messagebus  20   0 15188  4492 S    0.0  0.1  0:00.29 ├─ /usr/local/bin/dbus-daemon --system
  870 root        20   0 14120  2456 S    0.0  0.0  0:00.06 ├─ /usr/sbin/moused -p /dev/psm0 -t auto
  898 ntpd        20   0 24564  5848 S    0.0  0.1  0:00.06 ├─ /usr/sbin/ntpd -p /var/db/ntp/ntpd.pid -c /etc/ntp.conf -f
  944 root        68   0 23508  9560 S    0.0  0.1  0:00.00 ├─ sshd: /usr/sbin/sshd [listener] 0 of 10-100 startups
  947 root        20   0 13944  2576 S    0.0  0.0  0:00.02 ├─ /usr/sbin/cron -s
  952 root        20   0 56736 23700 S    0.0  0.3  0:00.04 ├─ /usr/local/bin/sddm
  980 root        20   0  257M  124M S    1.0  1.5  0:04.83   ├─ /usr/local/libexec/Xorg -nolisten tcp -background none -
  993 root        23   0 50208 27572 S    0.0  0.3  0:00.02   └─ /usr/local/libexec/sddm-helper --socket /tmp/sddm-auth-4
  994 ykla        68   0 19992  4620 S    0.0  0.1  0:00.01      └─ /usr/local/bin/ck-launch-session /usr/local/bin/start
 1005 ykla        68   0  128M 67736 S    0.0  0.8  0:00.13         └─ /usr/local/bin/startplasma-x11
 1010 ykla        68   0  128M 68184 S    0.0  0.8  0:00.25            └─ /usr/local/bin/plasma_session
 1017 ykla        20   0  773M  190M S    0.0  2.3  0:01.33               ├─ /usr/local/bin/kded6
 1018 ykla        20   0  676M  262M S    0.0  3.2  0:30.96               ├─ /usr/local/bin/kwin_x11

有些程序并非为持续接收用户输入而设计,而是在启动后即与终端断开连接。例如,Web 服务器响应 Web 请求而非用户输入,邮件服务器是此类应用程序的另一个例子。这类程序被称为守护进程(daemon)。术语“daemon”来自希腊神话,代表一种非善非恶的实体,它默默执行有用的任务。因此,BSD 的吉祥物设计为身着运动鞋、手持草叉的快乐守护进程形象。在 Windows 系统中,这类程序被称为“服务”,可在任务管理器中查看。

这些长期在后台运行的服务通常命名为 xxxd,例如 sshdntpd,其中的 d 表示守护进程(daemon),这是 UNIX 系统的通用命名约定。例如,BIND 是 Berkeley Internet Name Domain,但实际执行的程序名为 named。Apache Web 服务器程序是 httpd,数据同步 Rsync 进程是 rsyncd。但这仅是命名约定,并无规范,如 cronsendmail 的进程都不带 d

查看进程

用户只能向自己拥有的进程发送信号,root 用户可以向任何进程发送信号。SIGKILL 和 SIGSTOP 信号无法捕获或忽略。特殊 PID:0 发送到同组所有进程,-1 发送到所有进程(root)或自己的所有进程。

要查看系统上运行的进程,可以使用 ps(1) 或 top(1)。FreeBSD 的 ps 基于 4.4BSD,BSD 风格关键字允许省略 -,如 ps auxww

要显示当前运行进程的静态列表(包括它们的 PID、内存使用量和启动命令),使用 ps(1)。要以交互方式显示所有运行进程并每隔几秒更新显示以查看系统运行状态,使用 top(1)。

默认情况下,ps(1) 仅显示由当前用户拥有、且具有控制终端的进程:

ps(1) 的输出由多列构成:

列名
说明

PID

进程 ID。PID 从 1 开始分配,递增至 99999 后回绕至起始值。若某个 PID 已被占用,则不会再次分配。

TT

程序运行所在的 tty。

STAT

程序的状态。

TIME

程序在 CPU 上运行的时间量,通常不是程序启动以来的经过时间,因为大多数程序在需要花费 CPU 时间之前会花费大量时间等待事件触发。

COMMAND

用于启动程序的命令。

有许多不同的选项可用于更改显示的信息。最有用的选项集之一是 auxww,其中:

选项
说明

a

显示所有用户的有控制终端的进程的信息。若系统设置 security.bsd.see_other_uids=0,则非 root 用户使用此选项将无法查看其他用户的进程。

u

显示进程属主的用户名和内存使用量。

x

显示守护进程的信息。

ps -auxww 示例:

选项 ww 可以使 ps(1) 显示每个进程的完整命令行,而非在超出屏幕宽度时截断。但是,因为内核中存储的命令行长度有限制,在某些情况下,使用带有 ww 选项的 ps 时,输出可能仍然被截断。对于内核线程,命令字段可能显示为 [ ] 包裹的名称。

top(1) 的输出如下:

输出分为两个部分。头部(示例命令为前 7 行)显示最后运行的进程的 PID、系统负载平均值(衡量系统繁忙程度的指标)、系统正常运行时间(自上次重启以来的时间)和当前时间。头部中的其他数字与运行中的进程数量、已使用的内存和交换空间数量,以及系统在不同 CPU 状态下花费的时间有关。如果加载了 ZFS 文件系统模块,ARC 行指示从内存缓存而非磁盘读取了多少数据。

头部下方是一系列列,包含与 ps(1) 输出类似的信息,如 PID、用户名、CPU 时间量和启动进程的命令。在默认情况下,top(1) 还显示进程占用的内存空间量,分为两列:一列用于总大小,一列用于驻留大小。总大小是应用程序需要的内存量,驻留大小是它当前实际使用的量。top(1) 默认每两秒自动更新显示,可以使用 -s 指定不同的间隔,如 -s4 将每隔 4 秒刷新一次。

在非常繁忙的系统上,top 可能显示略微滞后的信息,因为采样需要时间。

终止进程

与任何运行中的进程或守护进程通信的一种方式是使用 kill(1) 发送信号。有许多不同的信号;有些具有特定含义,而其他信号在应用程序的文档中描述。用户只能向自己拥有的进程发送信号,向其他人的进程发送信号会提示权限不足。例外是 root 用户,其可向任何进程发送信号。

操作系统也可以向进程发送信号。如果应用程序编写不当并试图访问不应访问的内存,FreeBSD 将向进程发送“段违规”信号(SIGSEGV)。如果应用程序编写为使用 alarm(3) 系统调用在一段时间后收到警报,它将收到“闹钟”信号(SIGALRM)。

两个信号可用于停止进程:SIGTERM 和 SIGKILL。因为进程可以读取信号、关闭可能打开的任何日志文件,并尝试在关闭前完成正在执行的操作,SIGTERM 是终止进程的较为温和的方式。在某些情况下,如果进程正在执行某些无法中断的任务,它可能会忽略 SIGTERM。

进程无法忽略 SIGKILL。向进程发送 SIGKILL 通常会立即停止该进程。

其他常用的信号是 SIGHUP、SIGUSR1 和 SIGUSR2。由于这些是通用信号,不同的应用程序会有不同的响应。例如,在更改 Web 服务器的配置文件后,需要告诉 Web 服务器重新读取其配置。重启 httpd 会导致 Web 服务器短暂停机。相反,应向守护进程发送 SIGHUP 信号来使其重新读取配置。请注意,不同的守护进程会有不同的行为,因此请参阅守护进程的文档以确定 SIGHUP 是否能达到预期的结果。

随意终止系统中的进程是危险行为。尤其 init(8),PID 1 是最特殊的。

命令的前台与后台运行

Ctrl+Z:将当前进程挂起(暂停),随后可使用 fg 命令将其恢复到前台:

附录:系统监控工具 htop

安装与配置

使用 pkg 二进制包管理器安装:

或使用 Port 从源代码构建安装:

htop 配置持久化

可通过界面或配置文件持久化 htop 的配置。需注意:在设置菜单中按 F10 保存后,若使用 Ctrl + C 退出 htop,已保存的设置将被丢弃;必须使用 F10 或 q 正常退出才能确保配置写入 ~/.config/htop/htoprc

也可以手动编辑用户目录下的 ~/.config/htop/htoprc 配置文件,添加以下内容以启用 CPU 频率和温度显示功能:

参考文献

课后习题

  1. 使用 ps auxtop 查看系统运行的进程,按用户进程与系统守护进程进行分类,分析两类进程在父进程关系和会话组上的特征差异。

  2. 使用 nicerenice 修改进程优先级,记录不同 nice 值对 CPU 密集型任务执行时间的影响,分析 FreeBSD 调度程序对优先级的处理机制。

  3. 编写一个简单的守护进程脚本,配置为 rc.d 服务,使用 service 命令启动、停止和查询其状态,记录服务生命周期管理的完整流程。

最后更新于