操作系统学习笔记----进程/线程模型
进程/线程模型
0. 概述
0.1 进程模型
多道程序设计
进程的概念、进程控制块
进程状态及转换、进程队列
进程控制----进程创建、撤销、阻塞、唤醒、...
0.2 线程模型
为什么引入线程
线程的组成
线程机制的实现
用户级线程、核心级线程、混合方式
1. 进程的基本概念
1.1 多道程序设计
允许多个程序同时进入内存运行,目的是为了提高CPU系统效率
1.2 并发环境与并发程序
并发环境:
一段时间间隔内,单处理器上有两个货两个以上的程序同时处于开始运行但尚未结束的状态,并且次序不是事先确定的。
并发程序:
在并发环境中执行的程序
1.3 进程的定义
定义:Process
进程是具有独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和CPU调度的独立单位。
进程又称任务
程序的一次执行过程
是正在运行程序的抽象
对CPU的抽象,将一个CPU变幻成多个虚拟的CPU
系统资源以进程为单位分配,如内存、文件、...
每个进程具有独立的地址空间
操作系统将CPU调度给需要的进程
查看当前系统中有多少个进程:
Linux:ps命令
1.4 进程控制块PCB
PCB:Process Control Block
又称:进程描述符、进程属性
操作系统用于管理控制进程的一个专门数据结构
记录进程的各种属性,描述进程的动态变化过程
PCB是系统感知进程存在的唯一标志
进程与PCB是一一对应的
进程表:所有进程的PCB集合
进程表的大小一般固定
并发度:最多支持多少个进程
PCB的内容包含什么:
进程描述信息
进程控制信息
所拥有的的资源和使用情况
CPU线程信息
进程描述信息
进程标识符(process ID)唯一,通常是一个整数
进程名,通常给予可执行文件名,不唯一
用户标识符(user ID)
进程组关系
进程控制信息
当前状态
优先级
代码执行入口地址
程序的磁盘地址
运行统计信息(执行时间、页面调度)
进程间同步和通信
进程的队列指针
进程的消息队列指针
所拥有的的资源和使用情况
虚拟地址空间的状况
打开的文件列表
CPU现场信息
寄存器值(通用寄存器、程序计数器PC、程序状态字PSW、栈指针)
指向该进程也标的指针
Linux:task_struct
2. 进程状态及状态转换
2.1 进程状态
运行态:进程占用CPU,并在CPU上运行
进程从就绪状态被调度后,进程进入运行状态
就绪态:进程已经准备好,已分配到所需资源,只要分配到CPU就能够立即运行
等待态(或阻塞态):正在执行的进程由于某些事件(I/O请求,申请缓存区失败)而暂时无法运行,进程受到阻塞。
在进程等待的条件满足时,进入就绪状态等待系统调用
创建态:
已完成创建一个进程所必要的工作,PID、PCB
但尚未同意执行该进程,因为资源有限
终止态:进程执行完成后,进程进入终止态
可完成一些数据统计工作
资源回收
挂起态(Suspend):用于调节负载
进程不占用内存空间,其进程映像交换到磁盘上保存
2.2 进程状态转换
-
就绪 --> 运行:调度程序选择一个新的进程运行
-
运行 --> 就绪:只有两种情况
1. 运行进程用完了时间片
2. 一个高优先级进程进入就绪状态,抢占正在运行的进程 -
运行 --> 等待:当一个进程等待某个事件发生时
1) 请求OS服务器
2) 对资源的访问尚不能进行
3) 等待I/O结果
4) 等待另一个进程提供信息 -
等待 --> 就绪:所等待的事件发生了
-
以下两种状态转换不可能发生
等待 --> 运行:操作系统在进行调度时不会从阻塞(等待)队列进行挑选进程执行,而是从就绪队列中选取。
就绪 --> 等待:就绪态虽然准备就绪,但是还没有执行,无法进入等待态。
2.3 进程状态模型
浅度睡眠可以接收信号,而深度睡眠不可以接收信号
2.4 进程队列
进程队列:
操作系统为每一类进程建立一个或多个队列
队列元素为PCB
伴随进程状态的改变,其PCB从一个队列进入另一个队列
等待态队列,多个等待队列等待的条件不同
就绪态队列也可以是多个
3. 进程控制
进程控制操作完成进程各状态之间的转换,由具有特定功能的原语完成。
原语(Primitive)
完成某种特定功能的一段程序,具有不可分割或不可中断性。即原语的执行必须是连续的,在执行过程中不允许被中断。----原子操作(atomic)
3.1 进程的创建
给新进程分配一个唯一标识以及进程控制块
为进程分配地址空间
初始化进程控制块
设置默认值(如:状态为New,...)
设置相应的队列指针
如:把新进程加到就绪队列链表中
3.2 进程的撤销
收回进程所占有的资源
关闭打开的文件、断开网络连接、回收分配的内存
撤销该进程的PCB
3.3 进程阻塞
处于运行状态的进程,在其运行过程中期待某一时间发生,如等待键盘输入、等待磁盘数据传输完成、等待其他进程发送消息。当被等待的事件未发生时,由进程自己执行阻塞原语,使自己由运行态变为阻塞态。
wait();
3.4 Unix的几个进程控制操作
fork() 通过复制调用进程(父进程)来建立新的进程,是最基本的进程建立过程
exec() 包括一系列系统调用,它们都是通过用一段新的程序代码覆盖原来的地址空间,实现进程执行代码的转换
wait() 提供初级进程同步操作,能使一个进程等待另外一个进程的结束
exit() 用来终止一个进程的运行
3.5 Unix的fork()实现
为子进程分配一个空闲的进程描述符
proc结构
分配给子进程唯一标识pid
以一次一页的方式复制父进程地址空间
弊端:Unix中从父进程复制到子进程的内容,好多都不需要。Linux采用了写时复制技术COW加快创建进程 Copy-On-Write
从父进程处继承共享资源,如打开的文件和当前工作目录等
将子进程的状态设为就绪,插入到就绪队列
对子进程返回标识符0
向父进程返回子进程的pid
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
pid_t pid;
pid = fork(); // 创建一个子进程
if (pid < 0) { // 出错
fprintf(stderr, "fork failed\\n");
exit(-1);
} else if (pid == 0) { // 子进程
execlp("/bin/ls", "ls", NULL);
} else {
wait(NULL); // 父进程等待子进程结束
printf("Child process complete\\n");
exit(0);
}
return 0;
}
父进程空间fork()返回的是子进程的PID号。
子进程空间fork()返回的是0
4. 深入理解进程概念
4.1 关于进程的讨论
进程的分类
系统进程:操作系统为管理一些资源而设定的进程,特点是优先级比较高,相对于用户进程优先被调度
用户进程
前台进程:用户打交道的进程
后台进程:操作系统初始化后设定的进程,在后台为客户提供服务
CPU密集型进程:需要大量计算的进程,如:游戏、画面渲染等
I/O密集型进程:经常需要输入输出、读盘等操作
进程层次结构
Unix进程家族树:init为根
4.2 进程与程序的区别
进程更能准确刻画并发,而程序不能
程序是静态的,进程是动态的
进程有生命周期,有诞生有消亡,是短暂的;而程序是相对长久的
一个程序可对应多个进程
进程具有创建其他进程的功能,而程序没有
4.3 进程地址空间
操作系统给每个进程都分配了一个地址空间
每个进程有自己独立的地址空间,不同的地址空间的地址是虚拟地址
4.4 进程映像(Image)
对进程执行活动全过程的静态描述:
由进程地址空间内容、硬件寄存器内容及与该进程相关的内核数据结构、内核栈组成。
用户相关:进程地址空间(包括代码段、数据段、堆和栈、共享库...)
寄存器相关:程序计数器、指令寄存器、程序状态寄存器、栈指针、通用寄存器等的值
内核相关:
静态部分:PCB及各种资源数据结构
动态部分:内核栈(不同进程在进入内核后使用不同的内核栈)
4.5 上下文(Context)切换
将CPU硬件状态从一个进程换到另一个进程的过程称为上下文切换。
进程运行时,其硬件状态保存在CPU上的寄存器中
寄存器:程序计数器、程序状态寄存器、栈指针、通用寄存器、其他控制寄存器的值
程序不运行时,这些寄存器的值保存在进程控制块PCB中;当操作系统要运行一个新的进程时,将PCB中的相关值送到对应的寄存器中。
5. 线程
5.1 线程的引入
构造服务器的三种方法:
模型 | 特性 |
---|---|
多线程 | 有并发、阻塞系统调用 |
单线程进程 | 无并发、阻塞系统调用 |
有限状态机 | 有并发、非阻塞系统调用、中断 |
开销的考虑
进程相关的操作:
创建进程
撤销进程
进程通信
进程切换
时间/空间开销大,限制了并发度的提高。
线程的开销小
创建一个新线程话费时间少,撤销也是
两个线程切换花费时间少
线程之间相互通信无须调用内核(同一进程内的线程共享内存和文件)
性能的考虑
多个线程,有的计算,有的I/O
多个处理器
5.2 线程的基本概念
进程的两个基本属性
资源的拥有者----进程还是资源的拥有者
CPU调度单位----线程继承了这一属性
线程:进程中的一个运行实体,是CPU的调度单位,有时将线程称为轻量级进程。
在同一进程增加了多个执行序列(线程)。
5.3 线程的属性
线程:
有标识符ID
有状态及状态转换
不运行时需要保护的上下文
有上下文环境:程序计数器等寄存器
有自己的栈和栈指针
同一个进程的不同线程,共享所在进程的地址空间和其他资源
可以创建、撤销另一个线程
程序开始是以一个单线程进程方式运行的。
6. 线程机制的实现
6.1 线程的实现
用户级线程
在用户空间建立线程库:提供一组管理线程的过程。
运行时系统:完成线程的管理工作(操作、线程表)
内核管理的还是进程,不知道线程的存在
线程切换不需要内核态特权
多线程编程接口,以线程库方式提供给用户,pthread
pthread_create()
pthread_exit()
pthread_join()
pthread_yield()
6.2 用户级线程小结
优点:
线程切换快
调度算法是用用程序特定的
用户级线程可运行在任何操作系统上(只需要实现线程库)
缺点:
内核只将处理器分配给进程,同一进程中的两个线程不能同时运行与两个CPU上
大多数系统调用是阻塞的,因此,由于内核阻塞进程,所以进程中所有线程也被阻塞
6.3 核心级线程
内核管理所有线程,并向应用程序提供API接口
内核维护进程和线程的上下文
线程的切换需要内核支持
以线程为基础进行调度:
如:Windows
混合模型
线程创建在用户空间完成
线程调度等在核心态完成
多个用户级线程多路复用多个内核级线程
7. 本章重点小结
7.1 进程
并发性 任何进程都可以与其他进程一起向前推进执行
动态性 进程是正在执行程序的实例
进程是动态产生、动态消亡的
进程在其生命周期内,在三种基本状态之间转换
独立性 进程是资源分配的一个独立单位
各进程的地址空间相互独立
交互性 指进程在执行过程中可能与其他进程产生直接或间接的关系
异步性 每个进程都以其相对独立的、不可预知的速度向前推进
进程映像 程序 + 数据 + 栈(用户栈、内核栈) + PCB
7.2 线程
多线程应用场景
线程基本概念、属性
线程实现机制
可再入程序(可重入):
可被多个进程同时调用的程序,具有下列性质:
是纯代码的,即在执行过程中自身不改变;调用它的进程应该提供数据区
8. 重点概念
进程、进程状态及状态转换、进程控制、进程控制块(PCB)、进程地址空间、进程上下文环境
线程、线程属性、用户级线程、核心级线程、pthreads、可重入程序、原语、Web服务器
参考:Coursera北京大学操作系统课程笔记