进程定义
最简单的说法就是一个运行中的程序。
一个进程是由什么组成,我们更需要理解的是一个进程的机器状态,也就是一个进程在执行的过程中它可以访问系统中的哪些部分?可以影响系统的什么组件?
一个非常明显的组件是内存(memory)。进程只有被操作系统载入到内存中才能执行,程序的指令是放在内存中的,进程读写的数据也是放在内存中。也就是说,进程可以寻址的内存(地址空间)也是进程的一部分。
进程另外的机器状态组件是寄存器(register),很多程序指令都操作寄存器,因此它们也是进程非常重要的一部分。有些特殊的寄存器值得一提,比如程序计数器(pc),栈指针(sp)
最后一部分是进程会访问持久化存储设备,如硬盘等,因此打开的文件描述符表也是进程的一部分。
进程api
一个现代的操作系统应该提供一系列的api来控制进程。
- 创建
- 销毁
- 等待(等待另外一个进程完成)
- 各式各样的控制(比如挂起一个进程,过一段时间后恢复它的执行)
- 状态(查看进程的状态,进程运行了多久,进程当前处于什么状态)
进程创建
从操作系统把存储设备中的程序加载到内存,到main函数中的第一行代码执行,操作系统为创建进程做了哪些事情?
程序在硬盘中,以可执行文件的格式存在,但操作系统加载程序,会去读可执行文件,把程序指令和一些初始化数据加载到内存中。
早期的操作系统加载程序,会一次性把可执行文件都载入到内存中去,现代的操作系统实现的是lazy加载,换句话说只是加载部分的程序(程序执行需要的指令或数据)进入内存。如果想理解lazy加载是如何工作的,需要了解操作系统的分页机制。
一旦程序的指令和数据载入到内存中,为了进程能够执行,操作系统还需要进行一些工作。
- 分配栈(stack)。stack在进程中,存储函数的局部变量,函数参数,返回地址等,相关重要。
- 分配堆(heap)。动态分配的内存,可以在进程执行的过程增长,存储数据。
- 一些关于IO方面的初始化工作。如在unix系统,每个进程都默认在创建时会打开三个文件描述符,标准输入,标准输出和错误输出。
在进行完上面的工作后,还有最后一项任务,找到程序的执行入口点(entry point, c++中的main函数),调整到main函数,控制系统将cpu的控制权转交给新创建的进程,程序开始它的执行。
进程状态
进程五状态
- initial.初始化。进程正在被创建
- runing.运行。进程获得cpu的控制权,在处理器中执行,意味它正在执行指令。
- ready。就绪。进程已经准备好执行,但是由于某些原因,操作系统没有选择它立刻执行,也就是它没有获得cpu的控制权。
- blocked。阻塞。进程执行了一些操作,使得它不能在处理器中执行,要等待一些事件完成。如io操作,使得进程阻塞,同时其他进程可以获得cpu的控制权,继续执行。
- finial。进程已经退出,不能再继续执行。但是进程有关的一些数据结构还没有被操作系统回收,如unix系统中的zombie状态。这个状态的存在,运行父进程可以检查子进程执行完毕的返回码,看看子进程是否成功执行。父进程调用wait函数,告诉操作系统可以回收已经结束的子进程的有关数据结构。