# 写在前面
本文主要介绍`Linux`系统下进程的基础知识
# 进程的介绍
平时写的 C 语言代码,通过编译器编译,最终它会成为一个可执行程序,当这个可执行程序运行起来后(没有结束之前),它就成为了一个进程。

程序是存放在存储介质上的一个可执行文件,而进程是程序执行的过程。进程的状态是变化的,其包括进程的创建、调度和消亡。<font color="#FF0000">**程序是静态的,进程是动态的**</font> 。
在 `Linux` 系统中,操作系统是通过进程去完成一个一个的任务,进程是管理事务的基本单元。进程拥有自己独立的处理环境(如:当前需要用到哪些环境变量,程序运行的目录在哪,当前是哪个用户在运行此程序等)和系统资源(如:处理器 CPU 占用率、存储器、I/O设备、数据、程序)。我们可以这么理解,公司相当于操作系统,部门相当于进程,公司通过部门来管理(系统通过进程管理),对于各个部门,每个部门有各自的资源,如人员、电脑设备、打印机等。
# 并发
并发,在操作系统中,一个时间段中有多个进程都处于以启动运行到运行完毕之间的状态。但,在任意一个时刻点上仍然只有一个进程在运行。
例如,在计算机上可以一边听歌一边上网,若他们可以同运行的话,就是并发
## 单道程序设计
所有进程一个一个排队执行,若进程 A 阻塞,那么进程 B 只能等待,即使 CPU 处于空闲的状态,所以这种模型在系统资源利用上极其不合理,在计算机发展历史上存在不久,就被淘汰了
## 多道程序设计
在计算机内存中同时存放几道相互独立的程序,他们在管理程序控制下,相互穿插运行。
**时间中断**是多道程序设计模型的理论基础, 并发时,任意进程在执行期间都不希望放弃 CPU , 因此系统需要一种强制让进程让出 <font color="#0000FF">**系统资源**</font> (如:处理器 CPU 占用率、存储器、I/O设备、数据、程序)的手段,时钟中断有硬件基础作为保障,对进程而言不可抗拒。操作系统中的中断处理函数,来负责调度程序执行。
在多道程序设计模型中,多个进程轮流使用CPU(分时复用CPU资源),而当下CPU的执行的指令的速度在人眼中看似是同时进行。
实质上,并发是宏观并行,微观串行! 而如今的多核处理器才是真正意义上的并行执行进程。
# 进程状态
从上面得多道程序设计模型可知,当程序 A 在运行得过程中可以分为以下几个状态
- (初始态、就绪态)
进程已经具备执行的一切条件,正在等待分配 CPU 的处理时间。
- 运行态
该进程正在占用 CPU 运行。
- 挂起态
进程因不具备某些执行条件而暂时无法继续执行的状态,让出CPU资源。
- 终止态
程序运行结束
上述几种状态转化得过程如下

为了让大家更好地这几种状态的转换,给大家举一个买火车票的例子。
`Mike` 匆忙地赶去火车站买火车票,太着急了,到了售票厅才发现忘记带身份证,这时候,就算 `Mike` 排队也没用,因为 `Mike` 不具备买票的条件(没带身份证),这时候的 `Mike` 属于<font color="#FF0000">挂起态</font>。
`Mike` 给它对象打电话,让她把身份证带过来,等会,身份证送到了,这时候,`Mike` 可以去排队买票了,只是时间到,`Mike` 就可以买票了,这时,`Mike` 属于<font color="#FF0000">就绪态</font>。而这过程是由<font color="#0000FF">挂起态转换到就绪态</font>。
等了 10 分钟,终于到 `Mike` 了,`Mike` 开始买票,这时候, `Mike` 属于<font color="#FF0000">执行态</font>。而这过程是由<font color="#0000FF">就绪态转换为执行态</font>。
而在买票的过程中,`Mike` 的对象打电话给他,让 `Mike` 也帮她买一张火车票,但是, `Mike` 没有她对象的身份证,接着,`Mike` 继续等他对象送身份证,这时候,`Mike`由<font color="#0000FF">执行态转换为挂起态</font>。
最后 `Mike` 完成了所有得任务,就变成了<font color="#FF0000">终止态</font>
假如是这么一种情况,`Mike` 买火车票是给公司的同事买的(需要买 100 多张票),在买着票的过程中(执行态),后面还有很多人在排队,后面排队的人肯定不爽,这时售票员就说,20分钟后,如果你还没处理完,请你到后面排队。结果,`Mike` 花了 20 分钟还是没有处理完,于是,乖乖地到后面重新排队,这时候,`Mike`由执行态转换为就绪态。
# 进程控制块
对于操作系统而言,它需要控制很多进程,同时,每个进程都有不同的状态,系统如何知道 A 执行完到 B 执行而不是 C?系统如何协调控制进程呢?
当我们运行一个程序使它成为一个进程时,系统会开辟一段内存空间存放与此进程相关的数据信息,而这个数据信息是通过结构体( `task_struct`,打开 `/usr/include/linux/sched.h` 可以找到 `task_struct` 的定义 )来存放,我们把这个存放进程相关数据信息的结构体称为[进程控制块](https://baike.baidu.com/item/%E8%BF%9B%E7%A8%8B%E6%8E%A7%E5%88%B6%E5%9D%97?fr=aladdin)。<font color="#FF0000">操作系统就是通过这个进程控制块来操作控制进程</font>
进程控制块是操作系统中最重要的记录型数据结构。<font color="#FF0000">进程控制块记录了用于描述进程进展情况及控制进程运行所需的全部信息,它是进程存在的唯一标志</font>。进程控制块里有很多信息,本文只列举一些较为重要的东西,其余请自行查阅
## 进程id
**每个进程都由一个进程号来标识**,其类型为 `pid_t`(无符号整型),进程号的范围:`0~32767`。进程号总是唯一的,但进程号可以重用。当一个进程终止后,其进程号就可以再次使用。

第一列就是进程号
系统允许一个进程创建新进程,新进程即为子进程,子进程还可以创建新的子进程,形成进程**树结构模型**。整个 `Linux` 系统的所有进程也是一个**树形结构**。树根是系统自动构造的,即在内核态下执行的 0 号进程,它是所有进程的祖先。进程号为 0 的进程通常是调度进程,常被称为交换进程`swapper`。由 0 号进程创建 1 号进程(内核态),1 号负责执行内核的部分初始化工作及进行系统配置,并创建若干个用于高速缓存和虚拟主存管理的内核线程。随后,1 号进程调用 `execve()` 运行可执行程序 `init`,并演变成用户态 1 号进程,即 `init` 进程。所以,在 `Linux` 下面所有的进程都由 `init` 进程直接或者间接创建。在后续的创建子进程中会再度叙述。
PCB进程控制块还记录了
- 文件描述符表,包含很多指向 file 结构体的指针
- 进程状态:初始态、就绪态、运行态、挂起态、终止态。
- 进程当前工作目录位置
- umask掩码
- 信号相关信息资源。
- 用户id和组id
# 环境变量
通过`env`指令可以列出进程中的全部环境变量,查看环境变量的方法`echo $(环境变量名)`
常见的环境变量有:
- PATH
代表命令的搜索路径。
- SHELL
当前的Shell解释器,通常为 `/bin/bash`
- TERM
当前终端类型,在图形界面终端下通常为`xterm`,终端类型决定了一些程序的输出显示方式,比如图形界面终端可以显示汉字,而字符终端一般不行。
- LANG
语言和locale,决定了字符编码以及事件、货币等信息的显示格式
- HOME
当前用户主目录的路径
# 参考
[一步步学习Linux多任务编程](https://blog.csdn.net/tennysonsky/article/details/45847551)
进程的介绍