进程是操作系统上非常重要的概念,所有系统上面跑的数据都会以进程的类型存在。在 Linux 系统当中:触发任何一个事件时,系统都会将它定义成为一个进程,并且给予这个进程一个 ID,称为 PID,同时根据触发这个进程的用户,给予这个 PID 一组有效的权限设置。
程序运行起来后,我们看不到也摸不着。因此 Linux 为我们提供了一系列方便的命名来查看正在运行的进程。首先是 ps 命令,比如 ps -l
命令能查看当前 bash 下的相关进程全部信息。如下:1
2
3
4
5$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 1000 2552 2538 0 80 0 - 1945 wait pts/0 00:00:00 bash
0 S 1000 9352 2552 0 80 0 - 1926 wait pts/0 00:00:00 bash
0 R 1000 9478 9352 0 80 0 - 1598 - pts/0 00:00:00 ps
另外,我们还可以用 pstree
命令来显示整棵进程树。
可以看到这里 init 进程是所有进程的根节点,使用ps
命令还能看到 init 的 PID 为 1 。当Linux启动的时候,init 是系统创建的第一个进程,这一进程会一直存在,直到我们关闭计算机。所有其他的进程都是由 init 进程衍生出来的。
上面提到所谓的“衍生出来的进程”正是 Linux 的父子进程的概念。当我们登录系统后,会取得一个 bash shell,然后我们利用这个 bash 提供的接口去执行另一个命令,例如 bash
或者 ps
等。那些另外执行的命令也会被触发成为 PID,那个后来执行的命令产生的 PID 就是“子进程”,而原本的 bash 环境下,就称为“父进程”了。
老进程成为新进程的父进程(parent process),而相应的,新进程就是老的进程的子进程(child process)。一个进程除了有一个PID之外,还会有一个PPID(parent PID)来存储的父进程 PID。如果我们循着 PPID 不断向上追溯的话,总会发现其源头是 init 进程。所以说,所有的进程也构成一个以 init 为根的树状结构。
我们使用 ps -o
命令来看一看现有的进程。
1 | $ ps -o pid,ppid,comm |
我所做的操作是在原来的 bash shell 中执行了 bash 命令,然后又执行了 ps 命令。我们可以看到,第二个进程 bash 是第一个进程 bash 的子进程,而第三个进程ps是第二个进程的子进程。
当计算机开机的时候,内核(kernel)只建立了一个 init 进程。Linux kernel 并不提供直接建立新进程的系统调用。剩下的所有进程都是 init 进程通过 fork 机制建立的。新的进程要通过老的进程复制自身得到,这就是 fork。fork 是一个系统调用。进程存活于内存中。每个进程都在内存中分配有属于自己的一片空间 (内存空间,包含栈、堆、全局静态区、文本常量区、程序代码区)。当一个程序调用 fork 的时候,实际上就是将上面的内存空间,又复制出来一个,构成一个新的进程,并在内核中为该进程创建新的附加信息 (比如新的 PID,而 PPID 为原进程的 PID)。此后,两个进程分别地继续运行下去。新的进程和原有进程有相同的运行状态(相同的变量值,相同的指令…)。我们只能通过进程的附加信息来区分两者。
程序调用 exec 的时候,进程清空自身的内存空间,并根据新的程序文件重建程序代码、文本常量、全局静态、堆和栈(此时堆和栈大小都为 0),并开始运行。
这个工作管理(job control)是用在 bash 环境下的,也就是说,当我们登录系统取得 bash shell 之后,在单一终端机下可以同时进行多个工作的行为管理。
假如我们只有一个终端,因此在可以出现提示符让你操作的环境就成为前台(foreground),至于其他工作就可以放在后台(background)去暂停或运行。
工作管理的意义在于将多个工作囊括在一个终端,并取其中的一个工作作为前台,来直接接收该终端的输入输出以及终端信号。 其他工作在后台运行。
直接将命令丢到后台执行:&
1 | $ping localhost > log & |
此时终端显示:
1 | [1] 9800 |
括号中的 1 表示工作号,而 9800 为 PID
将目前的工作丢到后台中“暂停”: [ctrl]+z
1 | $vim ~/.bashrc |
在vim的普通模式下,按下[ctrl]+z
的组合键
1 | [2]+ 已停止 vim ~/.bashrc |
查看目前的后台工作状态:jobs
其各个参数的含义如下
-l :同时列出PID的号码
-r:仅列出正在后台run的工作
-s:仅列出在后台stop的工作
例如我们执行
1 | $ jobs -l |
能看到目前有多少个工作在后台中,并且能看到这些工作的 PID。紧跟在 job number 后面的 +
代表最近放到后台的工作,-
代表最近最后第二个放到后台的工作,直接执行fg
的话会先取+
的
将后台工作拿到前台来处理:fg %jobnumber
1 | $cat > log & |
当我们运行第一个命令后,由于工作在后台,我们无法对命令进行输入,直到我们将工作带入前台,才能向 cat 命令输入。在输入完成后,按下 CTRL+D 来通知 shell 输入结束。
让工作在后台下的状态变成运行中:bg %jobnumber
管理后台工作中的工作:kill
信号可以通过 kill 传递给进程,信号值以下三个比较重要。
-1 重新加载 (SIGHUP)
-9 立刻删除 (SIGKILL)
-15 正常终止(SIGTERM)
可以使用
1 | $kill -SIGTERM 9800 |
或者
1 | $kill -15 %1 |
的方式来发送给工作。上面的两个命令,一个是发送给信号给 PID 9800 ,一个是发送信号值给工作号1,两者等价。
监控进程的变化:top
top 是一个很不错的程序查看工具,但不同于 ps 的静态结果输出,top 可以持续监测整个系统的进程工作状态,而且功能非常丰富,可以在 top 中输入?
查看更多功能按键。常用的有 P
以CPU使用资源排序,M
以物理内存使用排序。
常用的参数有 -d
可以修改进程界面更新的秒数,-p
可以指定某些个 PID 来进行查看监测。
-EOF-