目录
在许多地方对进程的定义都是这样的一句话:加载到内存中的程序、正在运行的程序、进程可以排队······
而要真正理解进程是什么,这一句话的解释远远不够。
在定义进程之前,先来理解程序,我们存储在计算机磁盘(当前,现在的设备多是固态硬盘,一个意思)的可运行程序是一个二进制文件,是要交给计算机的CPU来执行的,那么磁盘属于外设,根据冯诺依曼的计算机体系结构,外设不能直接和CPU传输数据,而是中间要经过内存。
那么,这个可运行程序就会加载到内存。
那么,加载到内存以后,这就是进程了吗?
事实上,我们可以同时启动多个程序,那么就意味着有多个程序被加载到内存。
那么,操作系统必定要对这些加载到内存中的程序做管理。
而提到管理,必然离不开“先描述、再组织”,即先面向对象,再数据结构。
于是,在一个程序加载到内存后,操作系统内核也会定义一个结构体变量跟踪管理这个程序。这个结构体变量称为进程控制块PCB(process control block),它内部包含这个进程的所有信息。
Linux中描述PCB的结构体是task_struct。
因此,进程真正的理解为:
(先描述,PCB是结构体,利用面向对象的思想)进程 = 内核PCB + 可执行程序。
(再组织,有了结构体,管理结构体利用数据结构)进程 = 内核数据结构(一般是链表) + 可执行程序。

Linux中task_struct结构体变量的内容大致分类:
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
那么,我们作为用户,如何查看进程信息。这里有一个逻辑关系,PCB是内核结构体变量,属于操作系统内部变量,因此只能使用系统调用接口system call做相关操作。
/proc/
如果你想查看PID为1的进程信息,你可以查看下面这个目录
/proc/1
ps axj
ps是process的缩写,功能是显示当前系统的进程状态。axj分别是-a、-x、-j三个参数。
新建一个目录,比如24915,在该目录下新建源文件,同时配置Makefile文件。
- [euto@VM-4-13-centos 24915]$ touch myprocess.c
- [euto@VM-4-13-centos 24915]$ ls
- myprocess.c
- [euto@VM-4-13-centos 24915]$ ls > Makefile
- [euto@VM-4-13-centos 24915]$ ls
- Makefile myprocess.c
配置Makefile文件。
- [euto@VM-4-13-centos 24915]$ cat Makefile
- myprocess:myprocess.c
- gcc -o $@ $^ -std=c99
- .PHONY:clean
- clean:
- rm -f myprocess
编辑源文件。
- [euto@VM-4-13-centos 24915]$ cat myprocess.c
- #include
- #include
-
- int main()
- {
- while(1)
- {
- printf("i am a process!\n");
- sleep(1);
- }
- return 0;
- }
编译完成后,执行该程序。
- [euto@VM-4-13-centos 24915]$ ./myprocess
- i am a process!
- i am a process!
- i am a process!
- i am a process!
- i am a process!
- i am a process!
- i am a process!
- i am a process!
- i am a process!
- i am a process!
- i am a process!
- ······
同时,再观察进程信息。
- [euto@VM-4-13-centos 24915]$ ps axj | head -1 && ps axj | grep myprocess
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- 28701 15839 15839 28701 pts/1 28701 T 1001 0:00 ./myprocess
- 17253 20133 20132 17253 pts/2 20132 S+ 1001 0:00 grep --color=auto myprocess
- //打印的第二行是因为,grep本身也是可执行程序,即进程,在执行grep的时候
- //这个可执行程序的参数带有myprocess的字眼
- //可以使用grep 的 -v选项过滤掉这一行
- [euto@VM-4-13-centos 24915]$ ps axj | head -1 && ps axj | grep myprocess | grep -v grep
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- 28701 15839 15839 28701 pts/1 28701 T 1001 0:00 ./myprocess
下面,为了方便观察进程,让打印进程的指令做循环操作,不断检测进程状态。
- //while true
- //do
- // a
- // b
- // ···
- //done
- [euto@VM-4-13-centos 24915]$ while :; do ps ajx | head -1 &&
- >ps ajx | grep myprocess | grep -v grep;
- >sleep 1;
- >done
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- ················
执行可执行程序myprocess后,观察到进程从无到有的过程:
- [euto@VM-4-13-centos 24915]$ while :; do ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep; sleep 1; done
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- 2569 9385 9385 2569 pts/1 9385 S+ 1001 0:00 ./myprocess
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- 2569 9385 9385 2569 pts/1 9385 S+ 1001 0:00 ./myprocess
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- 2569 9385 9385 2569 pts/1 9385 S+ 1001 0:00 ./myprocess
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- 2569 9385 9385 2569 pts/1 9385 S+ 1001 0:00 ./myprocess
我们已经知道PCB属于内核数据,想要访问PCB需要系统调用接口system call。获取PID的命令名为getpid。
- //执行man getpid查看相关信息
-
- GETPID(2) Linux Programmer's Manual GETPID(2)
- NAME
- getpid, getppid - get process identification
- SYNOPSIS
- #include
- #include
- pid_t getpid(void);
- pid_t getppid(void);
- ··········
结果显示getpid是2号手册的内容。
- //执行man man查看手册的描述
- 1 Executable programs or shell commands
- //2号手册描述系统调用接口的使用
- 2 System calls (functions provided by the kernel)
- 3 Library calls (functions within program libraries)
- 4 Special files (usually found in /dev)
- 5 File formats and conventions eg /etc/passwd
- 6 Games
- 7 Miscellaneous (including macro packages and conventions), e.g.
- man(7), groff(7)
- 8 System administration commands (usually only for root)
- 9 Kernel routines [Non standard]
修改源文件内容。
- [euto@VM-4-13-centos 24915]$ cat myprocess.c
- #include
- #include
- #include
- int main()
- {
- pid_t id = getpid();
- while(1)
- {
- printf("i am a process! id: %d \n",id);
- sleep(1);
- }
- return 0;
- }
和原来一样的操作打印进程信息,观察进程从无到有的过程:
- [euto@VM-4-13-centos 24915]$ while :; do ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep; sleep 1; done
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- 2569 18465 18465 2569 pts/1 18465 S+ 1001 0:00 ./myprocess
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- 2569 18465 18465 2569 pts/1 18465 S+ 1001 0:00 ./myprocess
程序运行结果显示:
- i am a process! id: 18465
- i am a process! id: 18465
- i am a process! id: 18465
- i am a process! id: 18465
- ·······
一般在Linux中,普通进程都有父进程且唯一,而一个进程可能是多个子进程的父进程。
- //查看getppid的使用方法
- man getppid
同上一个操作一样,修改源文件,观察进程信息。
- [euto@VM-4-13-centos 24915]$ ./myprocess
- i am a process! id: 23894,fid: 2569
- i am a process! id: 23894,fid: 2569
- ^C
- [euto@VM-4-13-centos 24915]$ ./myprocess
- i am a process! id: 23982,fid: 2569
- i am a process! id: 23982,fid: 2569
- ^C
- [euto@VM-4-13-centos 24915]$ ./myprocess
- i am a process! id: 23992,fid: 2569
- i am a process! id: 23992,fid: 2569
- ^C
不难发现,普通进程,每次启动后,PID都是随机变化的,但是父进程是唯一不变的。但是进程2569到底是什么程序呢?
- [euto@VM-4-13-centos 24915]$ ps ajx | head -1 && ps axj | grep 2569
- PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
- 2562 2569 2569 2569 pts/1 2569 Ss+ 1001 0:00 -bash
- 3778 26700 26699 3778 pts/2 26699 S+ 1001 0:00 grep --color=auto 2569
关于bash,bash是Shell的其中一种。
Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
Linux 的 Shell 种类众多,常见的有:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for Root(/sbin/sh)
Bash,也就是 Bourne Again Shell,由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。
Bash即命令解释器,在命令行启动的程序,都是Bash的子进程。