# 第六部分：进程、服务、计划任务与日志

## 进程管理

首先程序与进程是什么？程序与进程又有什么区别？

程序（program）：程序就是执行一系列有逻辑、有顺序结构的指令序列，可以实现某个功能。

进 程（process） ： 进 程 是 程 序 在 一 个 数据集合上 的 一次 执行过程 ， 在早 期的UNIX、Linux 2.4 及更早的版本中，它是系统进行资源分配和调度的独立基本单位。

就像做一道菜的菜谱（程序），当厨师按照这个菜谱（程序），把原材料（输入数据）进行加工和处理（洗、切、搅拌、煎、炒、烹、炸等），然后得到了一道菜（输出结果）。

这就是程序的一次执行，就是进程。当执行完毕的时候，进程就结束了。可见，程序是静态的，而进程是动态的。

简单来说，程序是为了完成某种任务而设计的软件，比如 vim 是程序。什么是进程呢？进程就是把程序执行一次。

程序只是一系列指令的集合，是一个静止的实体，而进程不同，进程有以下的特性：

动态性：进程的实质是一次程序执行的过程，有创建、撤销等状态的变化。而程序是一个静态的实体。  
并发性：进程可以做到在一个时间段内，有多个程序在运行中。程序只是静态的实体，所以不存在并发性。  
独立性：进程可以独立分配资源，独立接受调度，独立地运行。  
异步性：进程以不可预知的速度向前推进。  
结构性：进程拥有代码段、数据段、PCB（进程控制块，进程存在的唯一标志）。也正是因为有结构性，进程才可以做到独立地运行。

并发：在一个时间段内，宏观来看有多个程序都在活动，有条不紊的执行（每一瞬间只有一个在执行，只是在一段时间有多个程序都执行过）

并行：在每一个瞬间，都有多个程序都在同时执行，这个必须有多个 CPU 才行

引入进程是因为传统意义上的程序已经不足以描述 OS 中各种活动之间的动态性、并发性、独立性还有相互制约性。程序就像一个公司，只是一些证书，文件的堆积（静态实体）。

而当公司运作起来就有各个部门的区分，财务部，技术部，销售部等等，就像各个进程，各个部门之间可以独立运做，也可以有交互（独立性、并发性）。

而随着程序的发展越做越大，又会继续细分，从而引入了线程的概念，当代多数操作系统Linux 2.6 及更新的版本中，进程本身不是基本运行单位，而是线程的容器。就像上述所说的，每个部门又会细分为各个工作小组（线程），而工作小组需要的资源需要向上级（进程）申请。

线程（thread）是操作系统能够进行运算调度的最小单位。它被包含在进程之中，是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流，一个进程中可以并发

多个线程，每条线程并行执行不同的任务。因为线程中几乎不包含系统资源，所以执行更快、更有效率。

简而言之,一个程序至少有一个进程,一个进程至少有一个线程。线程的划分尺度小于进程，使得多线程程序的并发性高。另外，进程在执行过程中拥有独立的内存单元，而多个线程共享内存，从而极大地提高了程序的运行效率。就如下图所示：

大概明白进程是个什么样的存在后，我们需要进一步了解的就是进程分类。可以从两个角度来分：

以进程的功能与服务的对象来分；  
： 以应用程序的服务类型来分；

第一个角度来看，我们可以分为用户进程与系统进程：

用户进程：通过执行用户程序、应用程序或称之为内核之外的系统程序而产生的进程，此类进程可以在用户的控制下运行或关闭。  
系统进程：通过执行系统内核程序而产生的进程，比如可以执行内存资源分配和进程切换等相对底层的工作；而且该进程的运行不受用户的干预，即使是 root 用户也不能干预系统进程的运行。

第二角度来看，我们可以将进程分为交互进程、批处理进程、守护进程

交互进程：由一个 Shell 终端启动的进程，在执行过程中，需要与用户进行交互操作，可以运行于前台，也可以运行在后台。  
批处理进程：该进程是一个进程集合，负责按顺序启动其他的进程。  
守护进程：守护进程是一直运行的一种进程，在 Linux 系统启动时启动，在系统关闭时终止。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。例如 httpd 进程，一直处于运行状态，等待用户的访问。还有经常用的 计划 任 务 进 程 cron（crond） 和 anacron（anacrond） ， 这 个 进 程 是守护进 程（daemon），可以按照计划周期性的执行用户设定的某些任务。

关于父进程与子进程便会提及这两个系统调用 fork() 与 exec()

fork-exec 是由 Dennis M. Ritchie 创造的

fork() 是一个系统调用（system call），它的主要作用就是为当前的进程创建一个新的进程，这个新的进程就是它的子进程，这个子进程除了父进程的返回值和 PID 以外其他的都一模一样，如进程的执行代码段，内存信息，文件描述，寄存器状态等等

exec() 也是系统调用，作用是切换子进程中的执行程序也就是替换其从父进程复制过来的代码段与数据段

既然子进程是通过父进程而衍生出来的，那么子进程的退出与资源的回收定然与父进程有很大的相关性。当一个子进程要正常的终止运行时，或者该进程结束时它的主函数 main()会执行 exit(n); 或者 return n，这里的返回值 n 是一个信号，系统会把这个 SIGCHLD 信号传给其父进程，当然若是异常终止也往往是因为这个信号。

在将要结束的时候，子进程代码部分已经结束执行了，系统的资源也基本归还给系统了，但若是其进程的进程控制块（PCB）仍驻留在内存中，代表这个进程还存在（因为 PCB 就是进程存在的唯一标志，里面有 PID 等信息），并没有消亡，这样的进程称之为僵尸进程（Zombie）。

正常情况下，父进程会收到两个返回值：exit code（SIGCHLD 信号）与 reason fortermination（结束原因） 。之后，父进程会使用系统调用wait(&status) 获取子进程的退出状态，然后内核从内存中释放已结束子进程的 PCB；而如若父进程没有这么做的话，子进程的 PCB 就会一直驻留在内存中，一直留在系统中成为僵尸进程（Zombie）。

虽然僵尸进程是已经放弃了几乎所有内存空间，没有任何可执行代码，也不能被调度，仅在进程列表中保留一个位置，记载该进程的退出状态等信息供其父进程收集，从而释放它但是 Linux 系统中能使用的 PID 是有限的，如果系统中存在有大量的僵尸进程，系统将会因为没有可用的 PID 从而导致不能产生新的进程。

另外如果父进程结束（非正常的结束），未能及时收回子进程，子进程仍在运行，这样的子进程称之为孤儿进程。在 Linux 系统中，孤儿进程一般会被 init 进程所“收养”，成为init 的子进程。由 init 来做善后处理，所以它并不至于像僵尸进程那样无人问津，不管不顾，僵尸进程大量存在会有危害。

进程 0 是系统引导时创建的一个特殊进程，也称之为内核初始化，其最后一个动作就是调用fork() 创建出一个子进程运行 /sbin/init 可执行文件,而该进程就是 $\mathsf { P I D } { = } 1$ 的进程 1，而进程 0 就转为交换进程（也被称为空闲进程），进程 1 （init 进程）是第一个用户态的进程，再由它不断调用 fork() 来创建系统里其他的进程，所以它是所有进程的父进程或者祖先进程。同时它是一个守护程序，直到计算机关机才会停止。

每一个进程都会是一个进程组的成员，而且这个进程组是唯一存在的，他们是依靠PGID（process group ID）来区别的，而每当一个进程被创建的时候，它便会成为其父进程所在组中的一员。

一般情况，进程组的 PGID 等同于进程组的第一个成员的 PID，并且这样的进程称为该进程组的领导者,也就是领导进程，进程一般通过使用 getpgrp() 系统调用来寻找其所在组的PGID，领导进程可以先终结，此时进程组依然存在，并持有相同的 PGID，直到进程组中最后一个进程终结。

与进程组类似，每当一个进程被创建的时候，它便会成为其父进程所在 Session（会话）中的一员，每一个进程组都会在一个 Session 中，并且这个 Session 是唯一存在的，

Session 主要是针对一个 tty 建立，Session 中的每个进程都称为一个工作(job)。每个会话可以连接一个终端(control terminal)。当控制终端有输入输出时，都传递给该会话的前台进程组。Session 意义在于将多个 jobs 囊括在一个终端，并取其中的一个 job 作为前台，来直接接收该终端的输入输出以及终端信号。 其他 jobs 在后台运行。

前台（foreground）就是在终端中运行，能够与用户进行输入和输出的交互

后台（background）就是在终端中运行，但是不能与其进行任何的交互，也不会显示其执行的过程

我们都知道当一个进程在前台运作时我们可以用 $\mathsf { c t r l } + \mathsf { c }$ 来终止它，但是若是在后台的话就不行了。

我们可以通过& 这个符号，让我们的命令在后台中运行

ll &

图中所显示的 [1] 236 分别是该 job 的 job number 与该进程的 PID，而最后一行的 Done表示该命令已经在后台执行完毕。

还可以通过 $\mathsf { c t r l } + \mathsf { z }$ 使当前工作停止并调到后台中去。

被停止并放置在后台的工作可以使用jobs命令查看。（这里的描述有问题，应该是放置在后台的工作，因为在后台运行的工作也可以）

jobs

其中第一列显示的为被放置后台 job 的编号，而第二列的 $+$ 表示最近(刚刚、最后)被放置后台的 job，同时也表示预设的工作，也就是若是有什么针对后台 job 的操作，首先对预设的 job，- 表示倒数第二（也就是在预设之前的一个）被放置后台的工作，倒数第三个（再之前的）以后都不会有这样的符号修饰，第三列表示它们的状态，而最后一列表示该进程执行的命令。

可以通过 fg 命令将后台的工作调到前台来。

#后面不加参数提取预设工作，加参数提取指定工作的编号

#ubuntu 在 zsh 中需要 $\%$ ，在 bash 中不需要 $\%$

fg [%jobnumber]

之前通过ctrl + z 使得工作停止放置在后台，若是想让其在后台运作，可以使用如下命令：

#与fg类似，加参则指定，不加参则取预设

bg [%jobnumber]

既然有方法将被放置在后台的工作提至前台或者让它从停止变成继续在后台运行，当然也有方法删除一个工作，或者重启等等。

#kill的使用格式如下

kill -signal %jobnumber

#signal 从 1-64 个信号值可以选择，可以这样查看

kill -l

中常用的有这些信号值：

<table><tr><td>信号值</td><td>作用</td></tr><tr><td>-1</td><td>重新读取参数运行，类似与restart</td></tr><tr><td>-2</td><td>如同ctrl+c的操作退出</td></tr><tr><td>-9</td><td>强制终止该任务</td></tr><tr><td>-15</td><td>正常的方式终止该任务</td></tr></table>

### kill 使用注意

若是在使用 kill+信号值+pid，将会对 pid 对应的进程进行操作

若是在使用 kill+信号值 $+ \%$ jobnumber，这时所操作的对象是 job，这个数字就是就当前bash 中后台的运行的 job 的 ID

kill -9 3 # 终止 3 号进程，pid $^ { = 3 }$

kill $- 9 \% 3$ # 终止 3 号 job，job $\therefore d = 3$

不管在测试的时候、在实际的生产环境中，还是自己的使用过程中，难免会遇到一些进程异常的情况，所以 Linux 为我们提供了一些工具来查看进程的状态信息。我们可以通过top 实时的查看进程的状态，以及系统的一些信息（如 CPU、内存信息等），我们还可以通过ps 来静态查看当前的进程信息，同时我们还可以使用 pstree 来查看当前活跃进程的树形结构。

top 工具是我们常用的一个查看工具，能实时的查看我们系统的一些关键信息的变化:

top

top 是一个在前台执行的程序，所以执行后便进入到这样的一个交互界面，正是因为交互界面我们才可以实时的获取到系统与进程的信息。在交互界面中我们可以通过一些指令来操作和筛选。在此之前我们先来了解显示了哪些信息。

load average 在 wikipedia 中的解释是 the system load is a measure of the amount ofwork that a computer system is doing 也就是对当前 CPU 工作量的度量，具体来说也就是指运行队列的平均长度，也就是等待 CPU 的平均进程数相关的一个计算值。

这是单个 CPU 单核的情况，而实际生活中我们需要将得到的这个值除以我们的核数来看。

我们可以通过以下的命令来查看 CPU 的个数与核心数

#查看物理CPU的个数

#cat /proc/cpuinfo |grep "physical id"|sort |uniq|wc -l

#每个 cpu 的核心数

cat /proc/cpuinfo |grep "physical id"|grep "0"|wc -l

通过上面的指数我们可以得知 load 的临界值为 1 ，但是在实际生活中，比较有经验的运维或者系统管理员会将临界值定为 0.7。这里的指数都是除以核心数以后的值，不要混淆了

通常我们都会先看 15 分钟的值来看这个大体的趋势，然后再看 5 分钟的值对比来看是否有下降的趋势。

查看busybox 的代码可以知道，数据是每5 秒钟就检查一次活跃的进程数，然后计算出该值，然后 load 从 /proc/loadavg 中读取的。而这个 load 的值是如何计算的呢，这是 load的计算的源码

CPU 利用率是对一个时间段内 CPU 使用状况的统计，通过这个指标可以看出在某一个时间段内 CPU 被占用的情况，而 Load Average 是 CPU 的 Load，它所包含的信息不是 CPU的使用率状况，而是在一段时间内 CPU 正在处理以及等待 CPU 处理的进程数情况统计信息，这两个指标并不一样。

NICE 值叫做静态优先级，是用户空间的一个优先级值，其取值范围是-20 至 19。这个值越小，表示进程”优先级”越高，而值越大“优先级”越低。nice 值中的 -20 到 19，中-20 优先级最高， 0 是默认的值，而 19 优先级最低

PR 值表示Priority 值叫动态优先级，是进程在内核中实际的优先级值，进程优先级的取值范围是通过一个宏定义的，这个宏的名称是 MAX_PRIO，它的值为 140。Linux 实际上实现了 140 个优先级范围，取值范围是从 0-139，这个值越小，优先级越高。而这其中的 0 -99 是实时进程的值，而 100 - 139 是给用户的。

其中 PR 中的 100 to 139 值部分有这么一个对应 $\mathsf { P R } = 2 0 + ( - 2 0 \mathsf { t o } + 1 9 )$ $+ 1 9 )$ ，这里的 -20 to$+ 1 9$ 便是 nice 值，所以说两个虽然都是优先级，而且有千丝万缕的关系，但是他们的值，他们的作用范围并不相同

** VIRT **任务所使用的虚拟内存的总数，其中包含所有的代码，数据，共享库和被换出swap 空间的页面等所占据空间的总数

ps 也是我们最常用的查看进程的工具之一，我们通过这样的一个命令来了解一下，他能给我带来哪些信息

ps aux

通过pstree 可以很直接的看到相同的进程数量，最主要的还是我们可以看到所有进程之间的相关性。

在Linux进程概念实验中讲述了进程如何衍生，进程之间的相关性，这里先回顾一下，当一个进程结束的时候或者要异常结束的时候，会向其父进程返回一个或者接收一个

SIGHUP 信号而做出的结束进程或者其他的操作，这个 SIGHUP 信号不仅可以由系统发送，我们可以使用 kill 来发送这个信号来操作进程的结束或者重启等等。

已经尝试过使用 kill 命令可以管理一些 job，这里尝试用 kill 来直接对进程的 pid 操作，但是前提是要知道进程的 pid。

#首先在桌面找到并打开 gedit、gvim，用 ps 可以查看到

ps aux

#使用 9 这个信号强制结束 gedit 进程

kill -9 1608

我们在使用 ps 命令的时候可以看到大部分的进程都是处于休眠的状态 S，如果这些进程都被唤醒，那么该谁最先享受 CPU 的服务，后面的进程又该是一个什么样的顺序呢？进程调度的队列又该如何去排列呢？

需要靠该进程的优先级值来判定进程调度的优先级，而优先级的值就是上文所提到的 PR与nice 来控制与体现了。

nice 的值可以通过 nice 命令来修改的，而需要注意的是 nice 值可以调整的范围是 -20 ~19。 root 账户既可以调整自己的进程也可以调整其他用户的程序，并且是所有的值都可以用，而普通用户只可以调制属于自己的进程，并且其使用的范围只能是 0 ~ 19，因为系统为了避免一般用户抢占系统资源而设置的一个限制。

#这个实验在环境中无法做，因为权限不够，可以自己在本地尝试

#打开一个程序放在后台，或者用图形界面打开

nice -n -5 vim &

#用 ps 查看其优先级

ps -afxo user,ppid,pid,stat,pri,ni,time,command | grep vim

copy

我们还可以用 renice 来修改已经存在的进程的优先级=

renice -5 pid

## 系统初始化

/etc/inittab

启动配置文件,每行分为四个域

code:runlevels:action:command

code－－用单个或两个字符序列作为本行的标识，在文件中是唯一的。而某些记录必须使用特定的code才能使系统工作正常。

runlevels－－本行的运行级别。

action－－指明 init 程序执行 command 的方式

command－－给出相应记录行要执行的命令

## 基础架构：服务、计划任务与日志

守护进程（Daemon）

始终在后台运行并响应合法请求的程序

SysVinit

Upstart

Systemd

使用 systemctl 管理服务

-缩写—全称

已运行的服务

为什么要安排调度进程任务

调度任务的守护进程

安排调度任务的

Crontab 文件

系统日常 的 cron 任务

系统日志服务

日志系统和系统体制

日志的用途

系统审计、检查测追踪和分析统计

日志的功能

用于记录系统、程序运行中发送的各种实践

通过阅读日志，有助于

日志系统

系统日志和内核消息捕捉的日志记录胸痛

主要功能

分类存放日志、方便日志管理

可将日志消息记录到远程主机

Rsyslog 采用模块化设计，是 syslog 的替代品

实现了基本的 syslog 协议

输入模块

Imklg、imsock、imfile、imtcp

预处理模块

主队列

过滤模块

执行队列

输出模块

全局指令

模板

输出通道

规则

Facility.priority action 动作

日志级别

### 系统管理命令速记

磁盘存储

统计/statistic

wc [-clw] file_list

Ex: ls -l | wc –l

磁盘存储/Disk store

df disk usage

du disk space

文件系统装卸/mount/unmount

Ex: mount –t iso9660 /dev/cdrom /mnt/cdrom

umount /dev/cdrom

别名/alias

give alias name to complicated command

alias myls=‘ls –l | more’
