文章目录
多道程序设计Multi-programming
多道程序设计目标:提高系统效率(吞吐量)
“道”:允许进入系统的程序的个数
单道:一次只允许一个程序进入系统
多道:一次允许多个程序进入系统
单道程序设计的缺点
处理机利用率低
设备利用率低
内存利用率低
多道程序设计的提出
提高处理机、设备、内存等各种资源的利用率,从而提高系统效率。
增加同时运行程序的道数可以提高资源利用率,从而提高系统效率,但道数应与系统资源数量相当。
道数过少,系统资源利用率低。
道数过多,系统开销(system overhead)增大,程序响应速度下降。
多道程序设计的问题
- 处理机资源的管理
程序个数>处理机个数(如何分配?) - 存储资源的管理
地址空间的相对独立性、共享性
内存、外存(swap space)的分配与去配 - 设备资源管理
分配策略
IO控制
进程的引入Process
多道系统中的程序:
推进,暂停,推进,暂停,…….
暂停:保存现场(PSW+PC,寄存器)
推进:恢复现场(寄存器,PSW+PC)
暂停原因:(1) 自身原因:等待资源,启动IO
(2) 剥夺CPU—给其它程序运行机会
进程的概念
定义:
- 可参与并发执行的程序称为进程。
- 进程是具有一定独立功能的程序关于一个数据集合的一次运行活动。
定义强调两个方面:
- 动态:执行中的程序;(程序和进程的对比)
- 并发:可与其他进程同时执行。
并发 vs. 并行
-
并发:concurrent
宏观同时,“交替执行”,不要求多个CPU -
并行:parallel
微观同时,要求多个CPU
“并行算法”
进程与程序的联系与差别
-
进程与程序的联系
进程包括一个程序
进程存在的目的就是执行这个程序 -
进程与程序的差别
程序静态,进程动态
程序可长期保存,进程有生存期
一个程序可对应多个进程,一个进程只能执行一个程序
进程状态及状态转换
进程状态(基本状态)
运行态(RUN): 占有CPU正在向前推进
就绪态(READY): 可以运行,但未得到CPU
等待态(WAIT): 等待某一事件发生
- 状态转换
就绪→运行:获得处理机
运行→就绪:剥夺处理机
运行→等待:申请资源未得到,启动IO
等待→就绪:得到资源,IO中断
进程状态转换由操作系统完成,对用户是透明的;
进程在其生存期内经过多次状态转换,体现了进程的动态性和并发性。
进程控制
进程是一个独立的运行单位,也是操作系统进行资源分配和调度的基本单位。
它由三部分组成:PCB、程序段、数据段,其中最核心的是进程控制块(PCB)。
进程控制块(PCB)
标志进程存在的数据结构,其中保存系统管理进程所需的全部信息
- 进程控制块(process control block)
建立进程→建立PCB
撤销PCB→撤销进程 - PCB内容:(不同系统不尽相同)
进程标识(pid) 家族联系
进程状态 地址信息
现场信息 打开文件
调度参数 消息指针
所属用户(uid) 队列指针
进程的表记
定义:进程的程序(代码和数据)称为进程影像(Process Image)。
- 进程上下文(process context)
进程的物理实体与支持进程运行的物理环境统称为进程上下文
-PCB+程序
-系统环境:地址空间,系统栈,打开文件表,… - 上下文切换(context switch)
由一个进程的上下文转到另外一个进程的上下文
进程切换的过程就是进程上下文切换的过程 - 系统开销(system overhead)
运行操作系统程序完成系统管理工作所花费的时间和空间
进程的队列
PCB构成的队列:(不一定FIFO,单向或双向)
- 就绪队列:系统一个或若干个(根据调度算法确定)
- 等待队列:每个等待事件一个
- 运行指示字:每个处理机一个
进程队列模型
进程的类型与特征
进程类型(从操作系统角度划分)
- 系统进程
运行操作系统程序,完成系统管理(服务)功能.
例如:UNIX #0 – sched, #1 – init - 用户进程
运行用户(应用)程序,为用户服务。
例如:UNIX vi, shell, cc
进程的特征
并发性:可以与其它进程一道向前推进;
动态性:动态产生、消亡,生存期内状态动态变化;
独立性:一个进程是可以调度的基本单位;
交往性:同时运行的进程可能发生相互作用;
异步性:进程以各自独立,不可预知的速度向前推进;
结构性:每个进程有一个PCB。
进程间相互联系与相互作用
相互联系
- 相关进程
同一家族的进程
可以共享文件,需要相互通讯,协调推进速度…
父进程可以监视子进程,子进程完成父进程交给的任务。 - 无关进程
没有逻辑关系、同时执行的进程。
有资源竞争关系,互斥、死锁、饿死。
相互作用
- 直接相互作用:发生在相关进程之间
- 间接相互作用:发生在任何进程之间
进程的创建与撤销
- 进程的创建
建立PCB,分配内存,加载程序,入就绪链
UNIX:pid=fork(),execl(prog,args) - 进程的撤销
去配资源,撤销PCB,通知父进程
UNIX:exit() vs. kill - 除初始进程外,其它进程由(父)进程创建,并形成进程家族。
系统调用
用户在程序中调用操作系统所提供的一些子功能
系统调用按功能可划分为:设备管理、文件管理、进程控制、进程通信、内存管理
系统调用处理要有操作系统内核完成,运行在核心态(通过陷入指令来发起)
UNIX有关进程的系统调用命令
相关系统调用
- 创建子进程
Pid = fork()
子进程是父进程的复制品
返回值:父进程为子进程编号,子进程为0 - 加载并执行新程序
execl(prog, arg0,…,argn-1,0)
以arg0,…,argn-1为参数执行prog
覆盖原来程序,从第一条指令开始执行 - 进程自我结束
exit(status)
Status为终止状态
唤醒父进程 - 等待子进程终止
pid=wait(&status)
返回终止子进程编号
参数为子进程的终止状态
在 UNIX 系统中通过系统调用fork可创建新进程。
-
新进程由原来进程的地址空间的复制组成,这种机制利于父进程与子进程方便进行通信。
-
两个进程都继续执行位于系统调用fork之后的指令
新进程返回值为0
父进程返回值为子进程的进程标识符(一个非0正整数)。 -
在UNIX系统中通常在系统调用fork 之后,新进程会使用系统调用execl ,来加载新程序。
-
windows NT操作系统支持两种方式
父进程地址空间可以被复制
或者父进程可以在创建进程时就提供程序名让操作系统把新程序直接装入新进程的地址空间。
# include <stdio.h>
void main ( int argc, char * argv[] )
{ int pid;
pid=fork ( );
if ( pid < 0) { printf ( stderr, “ fork failed” );
exit (-1 ); }
else if ( pid ==0 ) { execl (“/ bin /1s” , “ 1s” , null);}
else { wait (null);
print (“child complete”);
exit (0);}
fork()创建子进程
execl() 加载并执行新程序
exit() 进程自我终止
例子: 设有8个程序,执行次序如下图所示,试用fork,execl,wait,exit系统调用描述之.
main()
{
int pid1,pid2,pid3,pid4,pid5,pid6,pid7,pid8;
int end_p1=end_p2=end_p3=end_p4=end_p5=…=end_p8=0;
int pid, status;
if((pid1=fork())= =0) execl("P1",0);
wait(&status);
if((pid2=fork())= =0) execl("P2",0);
if((pid3=fork())= =0) execl("P3",0);
if((pid4=fork())= =0) execl("P4",0);
do{ //等待P2结束
pid=wait(&status);
if(pid= =pid2) end_p2=1;
if(pid= =pid3) end_p3=1;
if(pid= =pid4) end_p4=1;
}while(end_p2= =0);
if((pid5=fork())= =0) execl("P5",0);
if((pid6=fork())= =0) execl("P6",0);
do{ //等待P3和P6结束
pid=wait(&status);
if(pid= =pid3) end_p3=1;
if(pid= =pid4) end_p4=1;
if(pid= =pid5) end_p5=1;
if(pid= =pid6) end_p6=1;
}while(end_p3= =0||end_p6= =0);
if((pid7=fork())= =0) execl("P7",0);
do{ //等待P4,P5,P7结束
pid=wait(&status);
if(pid= =pid4) end_p4=1;
if(pid= =pid5) end_p5=1;
if(pid= =pid7) end_p7=1;
}while(end_p4= =0||end_p5= =0||end_p7= =0);
if((pid8=fork())= =0) execl("P8",0);
wait(&status);
exit(0);
}
vfork 与 fork
- fork 功能
复制地址空间(code+data+stack)
复制控制结构(proc,user) - 特点
父子进程之间有两个各自独立的数据拷贝 - 问题
不加载新程序 不能实现数据共享,不能描述诸如“有界缓冲区”问题
若加载新程序 复制没有意义,浪费时间和空间 - vfork
只复制控制结构(proc+user);
不复制地址空间(code+data)
父子进程共享地址空间 - 使用
父进程使用 vfork 创建子进程;
子进程与父进程共享地址空间;
子进程使用 execve 改变其虚拟地址空间.
考虑生灭的进程状态转换图
线程与轻进程 Thread and light-weighted process
线程的引入
进程切换
-上下文涉及内容多,开销大,“笨重”
PCB+程序
系统环境:地址空间,系统栈,打开文件表,
-相关进程之间耦合关系差
- 解决方案
Multi-threading
同一进程中包含多个线程
上下文只涉及寄存器和用户栈,切换速度快
相关线程之间通讯方便、快捷
线程的概念
- 进程中一个相对独立的执行流。
- 进程 vs.线程
进程是资源分配单位
线程是执行单位 - 多线程优点
切换速度快(地址空间不变)(light weighted)
系统开销小
通讯容易(共享数据空间)
线程结构
多进程结构(用户视图)
多线程结构(用户视图)
线程控制块
- TCB(Thread control block)
标志线程存在的数据结构,其中包含对线程管理需要的全部信息. - 内容
线程标识
线程状态
调度参数
现场(通用寄存器,PC,SP)
链接指针 - 存放位置
用户级线程:目态空间(运行时系统)
核心级线程:系统空间
线程的实现
用户级别线程
User-level thread
核心级别线程
Kernel-level thread
混合线程
Hybrid approach
用户级别线程
实现方法:
基于库函数,操作系统不可见
线程创建、撤销、状态转换在目态完成
TCB在用户空间,每个进程一个系统栈
优点:
不依赖于操作系统,调度灵活
同一进程中多线程切换速度快(不需进入操作系统)
缺点:
同一进程中多个线程不能真正并行
一个线程进入系统受阻,进程中其它线程不能执行
核心级别线程
实现方法:
基于系统调用
创建、撤销、状态转换由操作系统完成
优点:
同一进程内多线程可以并行执行(进程状态不再有意义)
一线程进入核心等待,其它线程仍可执行
缺点:
系统开销大,同一进程内多线程切换速度慢
调度算法不能灵活控制
混合线程
- Solaris例子
- User level thread用户级线程:
由库函数支持(创建,调度) - Light weighted process(LWP):
由Lib程序支持
每个task至少一个LWP
用戶级别线程与LWP可以多对多
LWP对操作系统可见
只有与LWP相联系的用户线程向前推进 - Kernel level thread内核级线程:
由kernel 支持
每个LWP与唯一一个核心线程对应
核心线程可与CPU多对多,可多对一
混合线程下的多线程模型
- 多对一:多个用户级线程映射到一个内核级线程
线程管理在用户空间进行,效率高
当一个线程被阻塞则多个线程不能并发 - 一对一:一个用户级线程映射到一个内核级线程
并发能力强
创建线程开销大,影响到应用程序的性能 - 多对多:多个用户级线程映射到多个内核级线程
线程的应用
内在的多控制流,需要共享数据
-生产-消费问题
多线程优于多进程
提高处理机与设备的并行性
多处理机环境
-提高处理机利用率,加快进程推进速度