OS-2 2.1进程
2.1 进程
1.进程的概念,特征和组成
a.进程的概念和特征
==程序:是静态的==,存放在磁盘里的*==可执行文件==*(一系列指令集合)。
==进程(process):动态的==(最本质的区别),是==程序的一次执行过程==。
==进程实体(进程映像):是静态的==,是进程在某一时刻的状态。
进程支撑起了OS两大基本特性:并发性和共享性。
- 解决了:①失去封闭性。②执行过程间断性。③结果不可再现性。
生命周期:一个进程在生命周期内可以执行一个或多个程序。
区别“一个进程**==执行==多个程序”≠“一个进程==运行==**多个程序”
- 串行执行:一个时刻只执行一个程序,是==先后替换关系==
- 不是并行:==不是同时运行==多个程序(那是多线程或多进程的事)
| 一个进程==执行==多个程序 | 同一个进程(PID 不变),先后运行不同的可执行文件 |
|---|---|
| 父子进程 | 一个进程创建另一个新进程(pid不同),==父子进程并发地执行,且不共享虚拟地址== |
| 进程切换 | CPU 在不同进程之间轮换执行,由操作系统调度 |
题目1:⭐
A. 一个进程在其生命周期中可执行多个程序√(见part1)
B. 一个进程在同一时刻可执行多个程序×
C. 一个程序的多次运行可产生多个进程√(打开多个网页)
D. 一个程序的一次执行可产生多个进程√(eg通过系统调用如fork()创建新的进程,此时就有了父进程和子进程)
题目2:
进程之间可能有相关性,也可能是相互独立的。
进程的相关性:血缘关系(父子) 或 协作关系(进程间通信)
进程的特征(相比于程序)
==动态性。==并发性。独立性。异步性。结构性。
==异步性:==并发进程每次运行时可能会有不同的结果。(执行速度的不同会造成进程执行顺序和冲突等问题)

b.进程实体 的组成(逻辑视角)
进程实体 == PCB + 程序段 + 数据段
PCB(process control block ==进程控制块==)
OS对进程进行管理工作所需的信息都保存在进程中。
==PCB是进程存在的唯一标志==。当进程被创建时,os为其创建PCB,当进程结束时,会回收PCB。
- PID:OS在创建一个进程时候,会给其一个ID,即PID。(用于区分同一软件的不同进程)
==PCB有四个部分:== ①进程标志信息。②进程控制信息。③资源分配信息。④CPU现场信息(各种寄存器的值) /上下文信息。
- 不包括:全局变量。

程序段、数据段
PCB是给OS用的。
程序段、数据段是给进程自己用的。
程序段:程序的指令。【进程间的程序段可以共享】
数据段:运行过程中产生数据。(运行时细分 – 数据段+堆+栈+共享库)【每个进程的数据段是私有的】
- EG:同时挂3个QQ,PCB和数据段不同,==但是程序段相同。==
c.进程的内存映像(运行时布局)
概念:程序被加载运行时,OS会为其建立一个**==虚拟的内存空间。==**
构成:
- ==代码段==:可执行==指令==、只读==常量==。
- ==数据段==:==全局变量,静态变量==。
- ==数据堆==:==动态内存==。(用malloc分配)(可动态扩展和收缩,向上增长)
- ==数据栈==:存放==局部变量==,==函数参数==等临时信息。(可动态扩展和收缩,向下增长)
- 共享库的存储映射区:存放内存映射文件。
==**进程控制块(PCB)**,不属于进程的虚拟地址空间,而是存放在内核区==,对用户不可见。
回顾

2.进程的状态与转换
进程/线程的状态:==创建 → 就绪 → 运行 → 阻塞 → 终止==
进程在 CPU 上的执行不是连续的(进程切换,阻塞…)
但进程的生命周期(从创建到终止)本身是连续的
进程的状态
==创建态:==进程被创建时,OS为进程分配资源,初始化PCB
- ==创建进程的原因有:==①用户登录,②高级调度,③系统处理用户程序的请求,④用户程序的应用请求。
- (设备分配:不会创建进程,是IO部分的事情。)
==就绪态:==进程创建完成后,为“就绪态”。**==有资源,无CPU。==**(CPU忙)
==运行态:== ==有资源 + 有CPU。==
==阻塞态:==
- 进程运行过程中,请求等待某个事件的发生 / 资源分配。(eg打印机响应)。
- 在事件发生前,进程无法继续执行,OS会让进程下CPU,并让它进入阻塞态,别的进程上CPU。
- 进入阻塞态后:==无CPU + 无资源==
==终止态:==进程执行exit系统调用,请求OS终止该进程,此时进程进入终止态。OS回收进程。

进程状态的转换
运行态→阻塞态,是==主动行为==。【由自身发起的系统调用触发。因此只有处于运行态的进程才能执行阻塞操作。】
阻塞态→就绪态,是==被动行为==。
==when运行态→就绪态==: ①时间片到时(==主动让出CPU)。②出现了进程优先级更高的进程。
==when运行态→阻塞态==:==① 进程主动等待资源分配(如IO,互斥/同步数据)。②或者等待某个事件发生(如sleep,wait)

题目2:
when一个进程状态的变化会引起 另一个 进程的变化:运行态→终止态
when一个进程状态的变化不会引起 另一个 进程的变化:阻塞态→就绪态
题目3:
(在分时系统中)处于就绪态的进程最多。(都在等待CPU,而阻塞态一般不会太多)
进程的组织
在实际OS中,通常存在着大量的进程,为进行调度和管理,OS将各进程的PCB以某种方式组织起来。
链接方式:系统将处于相同状态的PCB通过指针链接成一个队列。
索引方式:系统为每种状态建立一个索引表(本质上是一个数组),表项指向对应状态的PCB。
回顾

3.进程控制
a.进程控制和实现
==进程控制:实现进程状态转换==
==如何实现:用“原语”实现==
- 用原语的原因:原语的执行具有“原子性”,即“一气呵成”。【防止在第①步接收中断信号,导致信息不统一的情况。】
- 如何实现原语的“原子性”:通过特权指令“关中断”和“开中断”(屏蔽了外部中断信号)
==注:原语是一种特殊的程序。==

b.进程控制相关的原语
创建原语
- (允许一个进程创建另一个进程)子进程和父进程是相互独立⭐的实体,拥有各自的PCB和地址空间。
- ==父子进程:独立但需通信,开销大但安全可靠。==(fork())
- 进程与线程:共享但需同步,开销小但需谨慎管理并发安全。
- 引起进程创建的操作:用户登录。作业调度。提供服务。应用请求。(设备分配是数据结构实现的,no)

撤销原语

进程终止时,不同操作系统的对子进程的处理方式:
- 有的系统子进程终止。
- 有的系统(如Linux系统)子进程不终止而是由init进程(pid=1)收养继续执行。
阻塞原语和唤醒原语
阻塞原语往往包含“状态修改 + 调用切换原语”两个步骤
- 而切换原语也可以由其他原因触发(如时间片用完)
==阻塞和唤醒两个原语必须成对使用。==
某进程退出 临界区 后,之前因需要进入该临界区而被阻塞的有关进程会被唤醒
- 临界资源,一次只能给一个进程所用。

切换原语

回顾

4.进程通信
一个行不通的方法是全局变量,因为全局变量是相对于某一个进程而言的,不同进程有不同的全局变量。
==进程通信:两个进程之间产生数据交互==(eg抖音分享视频到微信)
进程通信需要OS支持:because各个进程拥有的内存地址空间是相互独立的
根据通信效率和数据量的不同,分为:
- 低级通信:传递控制信息(如同步,互斥),如PV操作。
- 高级通信:高效 传输大量数据。包括共享存储,消息传递和管道通信。
a.共享存储(2)
– A.基于存储器的共享
==申请一片共享内存区==,并映射到进程的虚拟地址空间。
需保证==各个进程对共享空间的访问是互斥的==。 (程序员/高级库/进程通过调用OS提供的同步原语来保证互斥,==通信进程自己实现互斥==)
共享存储是三种方式中==数据传输速度最快==的。(消息传递和管道都需通过内核中转)
(OS只负责分配,不提供同步保护)

– B.基于数据结构的共享

b.消息传递(2)
==数据交换 以==格式化的消息==(消息头,消息体)为单位。==
==进程通过==OS提供的==“发送消息/接收消息” 两个原语 进行数据交换==。
(目前广泛应用,eg微内核与服务器之间的交互就是基于消息传递)

直接通信方式
指明发送给谁,谁接收。

间接通信方式
以“信箱”作为中间实体进行消息传递。没有指明发送对象。

c.管道通信(1)
是一个特殊的 ==共享文件(pipe)==
- 但并非储存在磁盘中的文件,==是在 内存 中开辟出一个大小固定的内存缓冲区。==【与磁盘无关】
相比于共享存储通信方式:是FIFO的。单向的。**==【一条管道是半双工通信==】** (读取数据是一次性的)**==【共享存储是很多个收发口】==**。
①各进程互斥地访问管道**==【OS负责实现互斥】==(所以理论上是可以多进程访问的**,但是容易出错,所以用互斥保证单线程访问 )
②管道写满时,写进程将阻塞(读端read()返回0),till读进程取走部分数据。
②管道读空时,读进程将阻塞,till写进程写入新数据。【由此可见是固定大小的】**==【自动阻塞与唤醒】==**


回顾

d.信号
用于通知进程某个特定事件已经发生

基本概念:某个事件发生后,OS向进程发送信号。

实现原理:
A.信号的发送
用户进程之间可以发送信号(受权限限制)
OS内核也可以给用户发送信号(如异常、除零错误,定时器超时等)
进程也可以给自己发送信号

B.信号的保存和处理(when)
信号不是立即处理的,先保存在PCB中。
==进程从内核态返回用户态时==,会检查pending表。如果有信号,就==处理信号。==
- 优先处理序号较小的信号

C.信号的处理(HOW)
- ① 执行OS为此类信号设置的(默认)缺省信号处理程序(不过有的信号默认忽略不用处理)
- ② 执行进程为个别信号设置:用户自定义信号处理程序(将覆盖掉①)
- 自定义信号处理程序只能在自己的进程使用。
- 有些信号不支持自定义处理程序。(只能执行系统默认的处理程序)

Notes:
某个进程要阻塞的信号也不一样,自定。

==信号可以作为异常的配套机制,让进程对OS的异常处理进行补充==
- (当有的异常,OS无法由内核全部处理时,可能还需要用户进程的配合)

回顾⭐

5.线程
基本概念

线程 – 使进程并发pro
概念:
线程 ==不拥有== 独立的 ==系统资源(如(内存)地址空间,代码,数据)==
- 资源通过共享的方式获取。(eg代码段,数据段..)
但 ==拥有== 运行所必须的**==私有数据结构TCB==【包括:线程ID,CPU现场(PC,寄存器集合),栈…】
线程==可以独立执行程序==,但是==不能脱离进程进行==
进程VS线程:
- 线程变成了**==CPU调度和分派==的基本单位**(最小单位)。(内核级线程)
- 进程是**==资源分配==的基本单位**(eg打印机,内存分配)
线程优点:
==并发粒度更细==。(不仅仅进程能并发了,线程直接也能并发)
==系统开销变小==。(同一进程内的切换开销 小于 进程的切换开销)
线程缺点:
- ==无法增强进程安全性==(线程出错可能影响进程)
注意:
- 不能无约束地并行,得有互斥和同步,以免造成数据不一致。
线程的属性

线程的实现方式(2to3)

用户级 线程⭐
早期的线程os创建不了线程,是==线程库/用户程序实现的线程==。【不依赖于OS的支持,**==即不需要切换到内核态,在用户态实现的==**】
优点:①==效率高==(线程的切换不需要变态(到核心态))②调度策略由应用程序定制。③==有可移植性==(可以在任何操作系统中,不经修改,直接运行)
缺点:①==一个线程被阻塞,这个进程都会被阻塞,并发度不高==。②==利用不了多CPU的并行性==。

内核级线程
OS支持的线程,内核级线程。
==OS会为每个内核级线程建立相应的TCB==(thread control block),通过TCB对线程进行管理。
优点:①(同一个进程的)多线程可在多核处理机上运行。②阻塞处理灵活。③并发度高(适合I/O 密集型等高阻塞场景)
缺点:==效率低(线程的切换需要变态)==。
注意区分:==用户级线程切换,内核级线程切换==
多线程模型
用户级线程和内核级线程的组合。
一对一模型
一个用户级线程映射到一个内核级线程。
优点:当一个线程被阻塞,别的线程还可以继续执行,并发能力强。
缺点:开销大(变内核态)
多对一模型
多个用户级线程==映射到一个内核级线程==。
优点:用户级线程切换不用变态,开销小,效率高。
缺点:一个用户级线程被堵塞,整个进程被堵塞,并发度低。
多对多模型
n个用户级线程映射到m个内核级线程(n≥m)
优点:==克服了多对一的缺点(整体堵塞)==,==克服了一对一缺点(变态开销大)==
回顾

线程的状态与转换
基本上同进程的状态与转换

线程的组织与控制

