当你编译完一段代码生成 a.out 后,在命令行键入 ./a.out
,这时候,就有一个(或多个)新的进程产生了(前提你的 a.out 没问题^_^).
在此之前,a.out 文件只是一份保存在你硬盘上的死物而已,它并不是进程。一旦你在你的终端里键入./a.out
,你的终端 shell(它也是个进程,一个活物) 就会把 a.out 文件读到内存,一旦把控制权交给内存中的这段 a.out (称之为内存映像,它一硬盘上的 a.out 文件内容有些许区别,但是基本一致),于是 a.out 便开始执行了。
运行中的 a.out 是活物,它是进程(也许并不精确,但是这并不影响后面的学习)。
1. 看看有哪些活物
命令 ps -u allen u
可以帮助你查看当前系统中属于allen用户(有效用户 id)的进程,最后那个 u 表示显示格式,这里表示以用户格式显示。
需要注意的是,ps 后面的选项以短破拆号
-
开头和没有它开头的含义是不同的。一般来说,有-
开头的表示的是”UNIX options”,没有-
开头的叫 “BSD options”,而以双破折号--
开头的叫 “GNU long options”。
$ ps -u allen u
结果:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
allen 6273 0.0 0.1 6372 4068 ? Ss 10:19 0:00 /lib/systemd/systemd --user
allen 6274 0.0 0.0 25212 1508 ? S 10:19 0:00 (sd-pam)
allen 6330 0.0 0.1 13368 3296 ? S 10:19 0:01 sshd: allen@pts/1
allen 6331 0.0 0.2 7332 5100 pts/1 Ss 10:19 0:00 -bash
allen 6461 0.0 0.0 2200 512 pts/1 T 10:25 0:00 ./getmyid
allen 7492 0.0 0.1 13364 3272 ? S 13:38 0:00 sshd: allen@pts/2
allen 7493 0.0 0.2 7100 4620 pts/2 Ss 13:38 0:00 -bash
allen 7656 0.0 0.1 5320 3116 pts/2 S+ 13:56 0:00 man ps
allen 7668 0.0 0.0 4580 796 pts/2 S+ 13:56 0:00 pager
allen 7751 0.0 0.1 7752 3120 pts/1 R+ 14:10 0:00 ps -u allen u
从上面可以看到,当前属于 allen 用户的进程有 10 个。值得关注的是每一列的含义。下面以表格的形式给出。
- 各字段含义
名称 | 含义 |
---|---|
USER | 进程的属主 |
PID | 进程的 id 号 |
%CPU | 进程占用的 CPU 百分比 |
%MEM | 占用的内存百分比 |
VSZ | 进程虚拟大小 |
RSS | 驻留页的数量 |
TTY | 终端 id 号 |
STAT | 进程状态(D、R、S、T、W、X、Z、<、N、L、s 等) |
START | 进程开始运行时间 |
TIME | 累积使用的CPU时间 |
COMMAND | 使用的命令 |
- 进程状态值的含义( 从这里也可以看出,进程它是有状态的)
名称 | 含义 |
---|---|
D | 不可中断睡眠 |
R | 运行或就绪态 |
S | 休眠状态 |
T | 停止或被追踪 |
W | 进入内存交换(从内核2.6开始无效) |
X | 死掉的进程 |
Z | 僵尸进程 |
< | 优先级高的进程 |
N | 优先级较低的进程 |
L | 有些页被锁进内存 |
s | 进程的领导者(在它之下有子进程) |
由于 ps 命令非常复杂,将会单独以一篇文章来讲解,为了压缩文章篇幅,所以这里不介绍了。
2. 进程 id 号
作为一个中国公民,每个人都对应着一个身份证号,进程也一样,既然它是活物,就应该为它配备 id 号。前面的 ps 命令展示的结果,就可以看到进程的 id 号。进程的 id 号是唯一的。
每个进程都有父进程(除了 1 号进程(init进程)外),因为所有进程都是由另一个进程生出来的。
linux 系统提供了两个系统调用 getpid 和 getppid 来让我们查看当前进程的 id 和它的父进程 id.
2.1 实验
- 代码
// getmyid.c
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main() {
pid_t pid = getpid();
pid_t ppid = getppid();
printf("Process ID : %d\n", pid);
printf("Parent process ID : %d\n", ppid);
sleep(3);
return 0;
}
- 编译
$ gcc getmyid.c -o getmyid
- 运行
$ ./getmyid
- 结果
Process ID : 7878
Parent process ID : 6331
我们回到第 1 节中的 ps 命令的结果中查看,进程 6331 号是终端 pts/1 中的 bash 进程,而这个进程恰恰又是 getmyid 进程的父进程,这不是巧合,因为我刚刚在 pts/1 终端中键入了./getmyid
,这时 pts/1 中的 bash 进程生出了进程 7878 号进程 ./getmyid
。
3. 总结
- 知道进程位于内存里,它是活物
- 了解 ps 命令
- 进程是有状态的
- 每个进程都有 id 号
- 每个进程都有父进程(除了 1 号进程)