Linux基础:进程管理

进程是操作系统上非常重要的概念,所有系统上面跑的数据都会以进程的类型存在。在 Linux 系统当中:触发任何一个事件时,系统都会将它定义成为一个进程,并且给予这个进程一个 ID,称为 PID,同时根据触发这个进程的用户,给予这个 PID 一组有效的权限设置。

进程是什么样的

程序运行起来后,我们看不到也摸不着。因此 Linux 为我们提供了一系列方便的命名来查看正在运行的进程。首先是 ps 命令,比如 ps -l命令能查看当前 bash 下的相关进程全部信息。如下:

$ 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 命令来看一看现有的进程。

$ ps -o pid,ppid,comm
PID PPID COMMAND
2552 2538 bash
9352 2552 bash
9625 9352 ps

我所做的操作是在原来的 bash shell 中执行了 bash 命令,然后又执行了 ps 命令。我们可以看到,第二个进程 bash 是第一个进程 bash 的子进程,而第三个进程ps是第二个进程的子进程。

fork & exec

当计算机开机的时候,内核(kernel)只建立了一个 init 进程。Linux kernel 并不提供直接建立新进程的系统调用。剩下的所有进程都是 init 进程通过 fork 机制建立的。新的进程要通过老的进程复制自身得到,这就是 fork。fork 是一个系统调用。进程存活于内存中。每个进程都在内存中分配有属于自己的一片空间 (内存空间,包含栈、堆、全局静态区、文本常量区、程序代码区)。当一个程序调用 fork 的时候,实际上就是将上面的内存空间,又复制出来一个,构成一个新的进程,并在内核中为该进程创建新的附加信息 (比如新的 PID,而 PPID 为原进程的 PID)。此后,两个进程分别地继续运行下去。新的进程和原有进程有相同的运行状态(相同的变量值,相同的指令…)。我们只能通过进程的附加信息来区分两者。
程序调用 exec 的时候,进程清空自身的内存空间,并根据新的程序文件重建程序代码、文本常量、全局静态、堆和栈(此时堆和栈大小都为 0),并开始运行。

工作管理

这个工作管理(job control)是用在 bash 环境下的,也就是说,当我们登录系统取得 bash shell 之后,在单一终端机下可以同时进行多个工作的行为管理。

假如我们只有一个终端,因此在可以出现提示符让你操作的环境就成为前台(foreground),至于其他工作就可以放在后台(background)去暂停或运行。

工作管理的意义在于将多个工作囊括在一个终端,并取其中的一个工作作为前台,来直接接收该终端的输入输出以及终端信号。 其他工作在后台运行。

  • 直接将命令丢到后台执行:&

    $ping localhost > log &

    此时终端显示:

    [1] 9800

    括号中的 1 表示工作号,而 9800 为 PID

  • 将目前的工作丢到后台中“暂停”: [ctrl]+z

    $vim ~/.bashrc

    在vim的普通模式下,按下[ctrl]+z的组合键

    [2]+ 已停止 vim ~/.bashrc
  • 查看目前的后台工作状态:jobs
    其各个参数的含义如下
    -l :同时列出PID的号码
    -r:仅列出正在后台run的工作
    -s:仅列出在后台stop的工作

    例如我们执行

    $ jobs -l
    [1]- 9800 运行中 ping localhost > log &
    [2]+ 9905 停止 vim ~/.bashrc

    能看到目前有多少个工作在后台中,并且能看到这些工作的 PID。紧跟在 job number 后面的 + 代表最近放到后台的工作,- 代表最近最后第二个放到后台的工作,直接执行fg的话会先取+

  • 将后台工作拿到前台来处理:fg %jobnumber

    $cat > log &
    $fg %1

    当我们运行第一个命令后,由于工作在后台,我们无法对命令进行输入,直到我们将工作带入前台,才能向 cat 命令输入。在输入完成后,按下 CTRL+D 来通知 shell 输入结束。

  • 让工作在后台下的状态变成运行中:bg %jobnumber

  • 管理后台工作中的工作:kill
    信号可以通过 kill 传递给进程,信号值以下三个比较重要。
    -1 重新加载 (SIGHUP)
    -9 立刻删除 (SIGKILL)
    -15 正常终止(SIGTERM)

    可以使用

    $kill -SIGTERM 9800

    或者

    $kill -15 %1

    的方式来发送给工作。上面的两个命令,一个是发送给信号给 PID 9800 ,一个是发送信号值给工作号1,两者等价。

  • 监控进程的变化:top
    top 是一个很不错的程序查看工具,但不同于 ps 的静态结果输出,top 可以持续监测整个系统的进程工作状态,而且功能非常丰富,可以在 top 中输入?查看更多功能按键。常用的有 P 以CPU使用资源排序,M以物理内存使用排序。

    常用的参数有 -d 可以修改进程界面更新的秒数,-p可以指定某些个 PID 来进行查看监测。

参考资料

-EOF-