3.8.进程和守护进程

FreeBSD 是一个多任务的操作系统。在任何时候运行的每一个程序都被称为一个进程。每个正在运行的命令都会启动至少一个新的进程,并且有许多系统进程被 FreeBSD 所运行。

每个进程都由一个称为进程 ID(PID)的数字来唯一识别。与文件类似,每个进程都有一个所有者和组,所有者和组的权限被用来决定进程可以打开哪些文件和设备。大多数进程也有一个启动它们的父进程。例如,shell 是一个进程,在 shell 中启动的任何命令都是一个以 shell 为父进程的进程。例外的是一个叫做 init(8)的特殊进程,它总是在启动时第一个启动的进程,它的PID总是为1

有些程序的设计不是为了在用户连续输入的情况下运行,而是一有机会就断开与终端的连接。例如,网络服务器响应的是网络请求,而不是用户输入。邮件服务器是这种类型的应用程序的另一个例子。这些类型的程序被称为守护程序。守护进程这一术语来自希腊神话,代表了一个既非善也非恶的实体,它在无形中执行着有用的任务。这就是 BSD 的吉祥物是一个穿着运动鞋、拿着干草叉、看起来很欢快的守护者的原因。

有一个惯例是用尾部的d来命名那些通常作为守护程序运行的程序。例如,BIND 是伯克利互联网名称域,但实际执行的程序被命名为namedApache网络服务器程序是httpd,行式打印机的spooling daemonlpd。这只是一个命名惯例。例如,Sendmail 应用程序的主要邮件守护程序是sendmail,而不是maild

3.8.1.查看流程

要查看系统中运行的进程,使用 ps(1)或 top(1)。要显示当前正在运行的进程的静态列表、它们的 PID、它们正在使用多少内存以及它们是用什么命令启动的,使用 ps(1)。要显示所有正在运行的进程并每隔几秒钟更新一次,以便交互式地查看计算机正在做什么,使用 top(1)。

默认情况下,ps(1)只显示正在运行并由用户拥有的命令。比如说。

  1. % ps
  2. PID TT STAT TIME COMMAND
  3. 8203 0 Ss 0:00.59 /bin/csh
  4. 8895 0 R+ 0:00.00 ps

ps(1)的输出被组织成若干列。PID 列显示进程的 ID。PID 从 1 开始分配,一直到99999,然后再绕回开头。然而,如果一个 PID 已经被使用,则不会被重新分配。TT 列显示了程序正在运行的 tty,STAT 显示了程序的状态。TIME 是该程序在 CPU 上运行的时间。这通常不是程序启动后所经过的时间,因为大多数程序在需要在 CPU 上花费时间之前,会花很多时间来等待事情的发生。最后,COMMAND 是用来启动程序的命令。

有许多不同的选项可以改变所显示的信息。其中最有用的一组是auxwwa显示所有用户的所有运行进程的信息,u显示进程所有者的用户名和内存使用情况,x显示守护进程的信息,ww使ps(1)显示每个进程的完整命令行,而不是在它太长而无法在屏幕上显示时截断它。

top(1)的输出也类似。

  1. % top
  2. last pid: 9609; load averages: 0.56, 0.45, 0.36 up 0+00:20:03 10:21:46
  3. 107 processes: 2 running, 104 sleeping, 1 zombie
  4. CPU: 6.2% user, 0.1% nice, 8.2% system, 0.4% interrupt, 85.1% idle
  5. Mem: 541M Active, 450M Inact, 1333M Wired, 4064K Cache, 1498M Free
  6. ARC: 992M Total, 377M MFU, 589M MRU, 250K Anon, 5280K Header, 21M Other
  7. Swap: 2048M Total, 2048M Free
  8. PID USERNAME THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND
  9. 557 root 1 -21 r31 136M 42296K select 0 2:20 9.96% Xorg
  10. 8198 dru 2 52 0 449M 82736K select 3 0:08 5.96% kdeinit4
  11. 8311 dru 27 30 0 1150M 187M uwait 1 1:37 0.98% firefox
  12. 431 root 1 20 0 14268K 1728K select 0 0:06 0.98% moused
  13. 9551 dru 1 21 0 16600K 2660K CPU3 3 0:01 0.98% top
  14. 2357 dru 4 37 0 718M 141M select 0 0:21 0.00% kdeinit4
  15. 8705 dru 4 35 0 480M 98M select 2 0:20 0.00% kdeinit4
  16. 8076 dru 6 20 0 552M 113M uwait 0 0:12 0.00% soffice.bin
  17. 2623 root 1 30 10 12088K 1636K select 3 0:09 0.00% powerd
  18. 2338 dru 1 20 0 440M 84532K select 1 0:06 0.00% kwin
  19. 1427 dru 5 22 0 605M 86412K select 1 0:05 0.00% kdeinit4

输出被分成两部分。标题(前五或六行)显示了最后一个运行的进程的 PID,系统负载平均数(衡量系统有多忙),系统运行时间(自上次重启后的时间)和当前时间。标题中的其他数字涉及到有多少进程正在运行,有多少内存和交换空间被使用,以及系统在不同的 CPU 状态下花费了多少时间。如果ZFS文件系统模块已经被加载,ARC 行表明有多少数据是从内存缓存中而不是从磁盘中读取的。

在标题下面是一系列列,包含与 ps(1)输出的类似信息,例如 PID、用户名、CPU 时间和启动进程的命令。默认情况下,top(1)还显示进程占用的内存空间。这被分成两列:一列是总大小,一列是常驻大小。总大小是指应用程序需要多少内存,常驻大小是指它现在实际使用多少内存。

top(1)每两秒钟自动更新一次显示。可以用-s指定不同的间隔时间。

3.8.2.结束进程

与任何正在运行的进程或守护进程沟通的一种方式是使用 kill(1)发送信号。有许多不同的信号;一些信号有特定的含义,而其他信号则在应用程序的文档中描述。用户只能向自己的进程发送信号,向别人的进程发送信号会导致权限拒绝的错误。但根用户是个例外,他可以向任何人的进程发送信号。

操作系统也可以向进程发送一个信号。如果一个应用程序写得不好,并试图访问它不应该访问的内存,FreeBSD 将向该进程发送Segmentation Violation信号 (SIGSEGV)。如果一个应用程序被写成使用 alarm(3) 系统调用,在一段时间后被提醒,它将被发送“Alarm”信号 (SIGALRM)。

有两个信号可以用来停止一个进程。SIGTERM 和 SIGKILL。SIGTERM 是杀死一个进程的礼貌方式,因为该进程可以读取该信号,关闭它可能打开的任何日志文件,并试图在关闭前完成它正在做的事情。在某些情况下,如果一个进程正在进行一些不能被中断的任务,它可能会忽略 SIGTERM。

SIGKILL 不能被进程所忽略。向一个进程发送 SIGKILL 通常会使该进程立即停止。

其他常用的信号有 SIGHUP、SIGUSR1 和 SIGUSR2。由于这些是通用的信号,不同的应用程序会有不同的反应。

例如,在改变了一个 Web 服务器的配置文件后,需要告诉Web服务器重新读取其配置。重启 httpd 会导致网络服务器出现短暂的中断期。相反,向守护进程发送 SIGHUP 信号。请注意,不同的守护进程会有不同的行为,所以请参考守护进程的文档,以确定 SIGHUP 是否能达到预期效果。

Procedure:向一个进程发送信号。

这个例子显示了如何向 inetd(8) 发送一个信号。inetd(8) 的配置文件是/etc/inetd.conf,inetd(8) 在被发送 SIGHUP 时将重新读取这个配置文件。

1.使用 pgrep(1)找到要发送信号的进程的 PID。在这个例子中,inetd(8)的 PID 是 198。

  1. % pgrep -l inetd
  2. 198 inetd

2.使用 kill(1) 来发送信号。由于 inetd(8)是由 root 拥有的,所以先用 su(1)成为 root。

  1. % su
  2. Password:
  3. # /bin/kill -s HUP 198

像大多数 UNIX® 命令一样,如果成功 kill(1),也不打印任何输出。如果向一个不属于该用户的进程发送信号,将显示kill: PID: Operation not permitted将被显示。误填 PID 会将信号发送到错误的进程,这可能会产生负面的结果,或者将信号发送到一个当前没有使用的 PID,导致错误kill: PID: No such process

注意: 为什么使用/bin/kill?

许多 shell 将 kill 作为一个内置的命令,意味着将直接用 shell 发送信号,而不是运行/bin/kill。请注意,不同的 shell 有不同的语法来指定要发送的信号的名称。与其尝试学习所有这些语法,不如指定 /bin/kill 更简单。

发送其他信号时,用信号的名称代替 TERM 或 KILL。

重要: 杀死系统中的随机进程是一个坏主意。特别是 init(8),PID1,很特别。运行/bin/kill -s KILL 1是一个快速的、不推荐的关闭系统的方法。在按下返回键之前,一定要仔细检查 kill(1)的参数。