第二章(1) 进程
进程
严格来说,在某个瞬间,CPU只能运行一个进程。但在1秒钟之内,它可能运行多个进程,这样就产生并行的错觉,伪并行就是指这种场景,以此来区分多处理器系统(该系统有两个或多个CPU共享一个物理内存)的真正硬件并行。
进程模型
关键思想:一个进程是某种类型的活动,它有程序、输入、输出以及状态。单个处理器可以被若干进程共享,它使用某种调度算法决定何时停止一个进程的工作,并转而为另一个进程服务。
如果一个程序运行了两遍,则算两个进程。
进程的创建
有4种主要事件会导致进程的创建:
- 系统初始化
- 正在运行的程序执行了创建进程的系统调用
- 用户请求创建一个新进程
- 一个批处理作业的初始化
停留在后台处理的诸如电子邮件、Web页面、新闻等活动的进程称为守护进程
UNIX和Windows创建进程:
UNIX:
只有一个系统调用可以创建新进程——fork。这个系统调用会创建一个与调用进程相同的副本。在调用fork之后,这两个进程(父进程和子进程)拥有相同的内存映像,同样的环境字符串和同样的打开文件。这就是全部情形。通常,子进程接着执行execve或者一个类似的系统调用,以修改其内存映像并运行一个新程序。
进程创建之后,父进程和子进程有各自不同的地址空间。子进程的初始地址空间是父进程的一个副本,但是这里涉及两个不同的地址空间,不可写的内存区是共享的。
Windows:
一个Win32函数调用CreateProcess既处理进程的创建,也负责把正确的程序装入新的进程。子进程创建后,它的地址空间就与父进程的不同。
进程的终止
进程的终止通常由以下条件引起:
- 工作完成,正常退出(自愿)
- 出错退出(自愿)
- 严重错误(非自愿)
- 被其他进程杀死(非自愿)
杀死其它进程的进程必须获得确定的授权才可进行动作
进程的层次结构
Unix初始化过程:
一个称为init的特殊进程出现在启动映像中。当它开始工作时,读入一个说明终端数量的文件。接着,为每个终端创建一个新进程。这些进程等待用户登录。如果有一个用户登录成功,该进程就执行一个shell准备接受命令。所接受的命令就会启动更多的进程。
Unix的所有进程都属于init为根的一棵树。Unix中,进程不能剥夺其子进程的“继承权”。
Windows中没有进程层次的概念,所有进程的地位相同。在创建新进程时,父进程会得到一个特别的令牌(句柄),该句柄可以用来控制子进程。但它有权把这个句柄传给某个其它进程。
进程的状态
进程有三种状态:
- 运行态:该时刻进程实际占用CPU
- 就绪态:可运行,但由于其它进程正在运行而暂时停止
- 阻塞态:除非某种外部事件发生,否则进程不能运行
下图为三种进程状态的转换图:
- 进程由于等待输入而阻塞
- 调度程序选择另一个进程
- 调度程序选择这个进程
- 出现有效输入
进程的实现
为了实现进程模型,操作系统维护着进程表,每个进程占用一个进程表项。该表里包含进程状态的重要信息,比如程序计数器、堆栈指针、所打开文件的状态等待,包括了所有进程在运行态转换到就绪态或者阻塞态时必须保存的信息。
中断向量:中断服务程序的入口地址
中断发生后操作系统最底层的工作步骤:
- 硬件压入堆栈计数器等
- 硬件从中断向量装入新的程序计数器等
- 汇编语言过程保存寄存器值
- 汇编语言过程设置新的堆栈
- C中断服务例程运行(典型地读和缓冲输入)
- 调度程序决定下一个将运行的程序
- C过程返回至汇编代码
- 汇编语言过程开始运行新的当前进程