🌹😊🌹博客主页:【Hello_shuoCSDN博客】
✨操作系统详见 【操作系统专项】
✨C语言知识详见:【C语言专项】
目录
一、进程的概念、组成、特征
1.1 进程的概念(理解“进程”和“程序”的区别)
1.2 进程的组成
1.2.1 进程的组成——PCB
1.2.2 进程的组成——程序段、数据段
1.3 程序是如何运行的?
1.4 进程的特征
二、进程的状态与转换、进程的组织
2.1 进程的状态和状态的转换
2.1.1 进程的状态——创建态、就绪态
2.1.2 进程的状态——运行态
2.1.3 进程的状态——阻塞态
2.1.4 进程的状态——终止态
2.1.5 进程状态的转换
2.1.6 进程的状态
2.2 进程的组织
2.2.1 进程的组织——链接方式
2.2.2 进程的组织——索引方式
三、进程控制
3.1 进程控制的基本概念
3.1.1 什么是进程控制?
3.1.2 如何实现进程控制?
3.1.3 如何实现原语的 “原子性” ?
3.2 进程控制相关的原语
3.2.1 进程的创建
3.2.2 进程的终止
3.2.3 进程的阻塞和唤醒
3.2.4 进程的切换
3.2.5 程序是如何运行的(知识扩展)
四、进程通信
4.1 共享存储
4.2 消息传递
4.3 管道通信
一、进程的概念、组成、特征
1.1 进程的概念(理解“进程”和“程序”的区别)
程序:是静态的,就是个存放在磁盘里的可执行文件,就是一系列的指令集合。
进程(Process):是动态的,是程序的一次执行过程。(同一个程序多次执行会对应多个进程)
1.2 进程的组成
1.2.1 进程的组成——PCB
思考:操作系统是这些进程的管理者,它要怎么区分各个进程?
当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的 “身份证号” ——PID(Process ID,进程ID)
操作系统要记录PID、进程所属用户ID(UID)——基本的进程描述信息,可以让操作系统区分各个进程。
还要记录给进程分配了哪些资源(如:分配了多少内存、正在使用哪些1/0设备、正在使用哪些文件)——可用于实现操作系统对资源的管理。
还要记录进程的运行情况(如:CPU使用时间、磁盘使用情况、网络流量使用情况等)——可用于实现操作系统对进程的控制、调度。
这些信息都被保存在一个数据结构PCB(Process Control Block)中,即进程控制块。操作系统需要对各个并发运行的进程进行管理,但凡管理时所需要的信息,都会被放在PCB中。
1.2.2 进程的组成——程序段、数据段
PCB是给操作系统用的。
程序段、数据段是给进程自己用的。
1.3 程序是如何运行的?
当写完一个程序,编译链接后会形成一个可执行文件(Windows系统下的.exe可执行文件),可执行文件是存放在硬盘当中的,硬盘中保存的就是我们刚才的一些列指令序列,当程序想要运行的话需要把它从硬盘读到内存中,操作系统会建立一个与之相关的进程,会创建相应的PCB,另外一些列的指令序列也要读入到内存中,这一系列指令序列我们称为程序段,其实这个进程执行的过程就是CPU从内存当中读如一条一条的指令,来执行这一条一条指令的过程。因为在执行指令的过程中,还会产生一些中间的数据,如 (int x=1 ; x++后 x=2 )这些数据会放在数据段的区域。
一个进程实体(进程映像)由PCB、程序段、数据段组成。
进程是动态的,进程实体(进程映像)是静态的。
进程实体反应了进程在某一时刻的状态(如:x++后,×=2)
进程的组成
程序段、数据段、PCB三部分组成了进程实体(进程影像)
引入进程实体的感念后,可把进程定义为:进程是进程实体的运行过程,是系统进行资源分配和调度(一个进程被 “调度” 就是指操作系统决定让这个进程上CPU运行)的一个独立单位。
注意:PCB是进程存在的唯一标志!
1.4 进程的特征
程序是静态的,进程是动态的,相比于程序,进程拥有以下特征:
①:动态性——进程是程序的一次执行过程,是动态地产生、变化和消亡的
②:并发性——内存中有多个进程实体,各进程可并发执行
③:独立性——进程是能独立运行、独立获得资源、独立接受调度的基本单位
④:异步性——各进程按各自独立的、不可预知的速度向前推进,操作系统要提供“进程同步机制”来解决异步问题
⑤:结构性——每个进程都会配置一个PCB。结构上看,进程由程序段、数据段、PCB组成
动态性是进程最基本的特征
异步性会导致并发程序执行结果的不确定性。
小结:
二、进程的状态与转换、进程的组织
2.1 进程的状态和状态的转换
2.1.1 进程的状态——创建态、就绪态
进程正在被创建时,它的状态是“创建态”,在这个阶段操作系统会为进程分配资源、初始化PCB。
当进程创建完成后,便进入“就绪态”,处于就绪态的进程已经具备运行条件,但由于没有空闲CPU,就暂时不能运行。
2.1.2 进程的状态——运行态
如果一个进程此时在CPU上运行,那么这个进程处于“运行态”。
CPU会执行该进程对应的程序(执行指令序列)
假设进程2依次在CPU上执行指令1、指令2、指令3:发出系统调用,请求使用打印机资源、指令4:输出数据到打印机。但是这时的打印机处于工作占用状态,所以无法执行指令4,在获取所需资源之前,进程无法再往下执行。
2.1.3 进程的状态——阻塞态
在进程运行的过程中,可能会请求等待某个事件的发生(如等待某种系统资源的分配,或者等待其他进程的响应)。
在这个事件发生之前,进程无法继续往下执行,此时操作系统会让这个进程下CPU,并让它进入“阻塞态”。
当CPU空闲时,又会选择另一个“就绪态” 进程上CPU运行。
2.1.4 进程的状态——终止态
一个进程可以执行 exit 系统调用,请求操作系统终止该进程。
此时该进程会进入“终止态”,操作系统会让该进程下CPU,并回收内存空间等资源,最后还要回收该进程的PCB。当终止进程的工作完成之后,这个进程就彻底消失了。
2.1.5 进程状态的转换
阻塞态——>就绪态是不是进程自身能控制的,是一种被动行为。
运行态——> 阻塞态是一种进程自身做出的主动行为。
注意:不能由阻塞态直接转换为运行态,也不能由就绪态直接转换为阻塞态(因为进入阻塞态是进程主动请求的,必然需要进程在运行时才能发出这种请求)。
2.1.6 进程的状态
三种基本状态(进程的整个生命周期中,大部分时间都处于三种基本状态)
运行态(Running) 占有CPU,并在CPU上运行 。 (单CPU情况下,同一时刻只会有一个进程处于运行态,多核CPU情况下,可能有多个进程处于运行态)
就绪态 (Ready)已经具备运行条件,但由于没有空闲CPU,而暂时不能运行。
阻塞态(Waiting/Blocked, 又称:等待态)因等待某一事件而暂时不能运行。
另外两种状态
创建态(New,又称:新建态) 进程正在被创建,操作系统为进程分配资源、初始化PCB。
终止态(Terminated,又称:结束态)进程正在从系统中撤销,操作系统会回收进程拥有的资源、撤销PCB。
进程PCB中,会有一个变量state 来表示进程的当前状态。如:1表示创建态、2表示就绪态、3表示运行态为了对同一个状态下的各个进程进行统一的管理,操作系统会将各个进程的PCB组织起来。
2.2 进程的组织
2.2.1 进程的组织——链接方式
很多操作系统还会根据阻塞原因不同,再分为多个阻塞队列
2.2.2 进程的组织——索引方式
小结:
三、进程控制
3.1 进程控制的基本概念
3.1.1 什么是进程控制?
进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、‘撤销已有进程、实现进程状态转换等功能。
简化理解:反正进程控制就是要实现进程状态转换
3.1.2 如何实现进程控制?
进程控制是用 “原语” 实现的。
原语是一种特殊的程序,它的执行具有原子性。也就是说,这段程序的运行必须一气呵成,不可中断。
原语的执行具有“原子性”,一气呵成。
可以用 “原语” 来实现 “一气呵成”。
如果不能“一气呵成”,就有可能导致操作系统中的某些关键数据结构信息不统一的情况,这会影响操作系统进行别的管理工作.
⭐(扩展知识详见:计算机系统的层次结构(点我))
Eg:假设PCB中的变量 state 表示进程当前所处状态,1表示就绪态,2表示阻塞态⋯
假设此时进程2等待的事件发生,则操作系统中,负责进程控制的内核程序至少需要做这样两件事:
①将PCB2的 state 设为1
(完成了第一步后收到中断信号,那么PCB2中的state=1,但他却被放在阻塞队列里)
②将PCB2从阻塞队列放到就绪队列
3.1.3 如何实现原语的 “原子性” ?
原语的执行具有原子性,即执行过程只能一气呵成,期间不允许被中断。可以用“关中断指令”和“开中断指令”这两个特权指令实现原子性。
正常情况下指令会一条一条向下执行,有中断信号时,操作系统就会去执行中断信号,中断信号处理结束后转而继续执行相应程序。
正常情况:CPU每执行完一条指令都会例行检查是否有中断信号需要处理,如果有,则暂停运行当前这段程序,转而执行相应的中断处理程序。
CPU执行了关中断指令之后,就不再例行检查中断信号,直到执行开中断指令之后才会恢复检查。
这样,关中断、开中断之间的这些指令序列就是不可被中断的,这就实现了“原子性“。
思考:如果这两个特权指令允许用户程序使用的话,会发生什么情况?
当这两个特权指令允许用户程序使用的话,用户程序在CPU上运行就不会再受到中断信号的影响,那么该用户程序就会一直在CPU上面运行,霸占CPU。
3.2 进程控制相关的原语
3.2.1 进程的创建
创建原语:(操作系统创建一个进程时使用的原语)
① 申请空白PCB
② 为新进程分配所需资源
③ 初始化PCB
④ 将PCB插入就绪队列 (创建态——>就绪态)引起进程创建的事件:
用户登录——分时系统中,用户登录成功,系统会建立为其建立一个新的进程。
作业调度——多道批处理系统中,有新的作业放入内存时,会为其建立一个新的进程。
提供服务——用户向操作系统提出某些请求时,会新建一个进程处理该请求。
应用请求——由用户进程主动请求创建一个子进程。
3.2.2 进程的终止
撤销原语:(就绪态/阻塞态/运行态——>终止态——>无)
① 从PCB集合中找到终止进程的PCB
② 若进程正在运行,立即剥夺CPU,将CPU分配给其他进程③ 终止其所有子进程。(进程间的关系是树形结构)
④ 将该进程拥有的所有资源归还给父进程或操作系统
⑤ 删除PCB引起进程终止的事件:
正常结束——进程自己请求终止(exit系统调用)。
异常结束——整数除以O、非法使用特权指令,然后被操作系统强行杀掉。
外界干预——Ctrl+Alt+delete,用户选择杀掉进程。
关于父进程和子进程
3.2.3 进程的阻塞和唤醒
(阻塞原语唤醒原语必须成对使用)
一、进程的阻塞
1.阻塞原语(运行态——>阻塞态)
① 找到要阻塞的进程对应的PCB
② 保护进程运行现场,将PCB状态信息设置为"阻塞态",暂时停止进程运行③ 将PCB插入相应事件的等待队列
2.引起进程阻塞的事件
需要等待系统分配某种资源
需要等待相互合作的其他进程完成工作二.进程的唤醒
1.唤醒原语(阻塞态——>就绪态)
① 在事件等待队列中找到PCB
② 将PCB从等待队列移除,设置进程为就绪态
③ 将PCB插入就绪队列,等待被调度
2.引起进程唤醒的事件
等待的事件发生(因何事阻塞,就应由何事唤醒)
3.2.4 进程的切换
切换原语 (运行态——>就绪态)(就绪态——>运行态)
① 将运行环境信息(进程上下文(context))存入PCB
② PCB移入相应队列
③ 选择另一个进程执行,并更新其PCB
④ 根据PCB恢复新进程所需的运行环境
引起进程切换的事件
当前进程时间片到
有更高优先级的进程到达
当前进程主动阻塞当前进程终止
3.2.5 程序是如何运行的(知识扩展)
CPU中会设置很多“寄存器”,用来存放程序运行过程中所需的某些数据。
指令1、指令2、指令3....这些指令在顺序执行的过程中,很多中间结果是放在各种寄存器中的。
思考:执行完指令3后,另一个进程开始上CPU运行。另一个进程在上CPU上运行的时候,有可能会把前一个进程在寄存器中保留的中间结果给覆盖住。
注意:另一个进程在运行过程中也会使用各个寄存器。
解决办法:在进程切换时先在PCB中保存这个进程的运行环境(保存一些必要的寄存器信息)
当原来的进程再次投入运行时,可以通过PCB恢复它的运行环境。
无论哪个进程控制原语,要做的无非三类事情:
1.更新PCB中的信息(修改进程状态(state)保存/恢复运行环境)
2.将PCB插入合适的队列
3.分配/回收资源
小结:
四、进程通信
什么是进程间通信?
进程间通信 (Inter-Process Communication,IPC)是指两个进程之间产生数据交互。
为什么进程通信需要操作系统支持?
进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立。
当进程P想要和Q进行数据之间的传输时,两个进程不能直接进行数据之间的访问,好比手机中如果不小心下载了一个垃圾软件的话,进程间如果可以直接进行数据访问就有可能垃圾软件访问手机照片,电话微信数据等...造成信息的泄露。所以,为了保证安全,一个进程不能直接访问另一个进程的地址空间。
既然两个进程之间不能直接进行,下面我们就来介绍三种进程通信的方式:共享存储、消息传递、管道通信。
4.1 共享存储
(基于数据结构的共享、基于存储区的共享)
进程申请一块共享存储区,而这片共享存储区也可以被其他进程所共享,这样一来,进程P先申请一片共享存储区把数据写入进去,然后进程Q再从共享存储区中读出数据,通过共享存储区来实现数据之间的交换。
为避免出错,各个进程对共享空间的访问应该是互斥的。
各个进程可使用操作系统内核提供的同步互斥工具(如P、V操作)
注:通过“增加页表项/段表项”即可将同一片共享内存区映射到各个进程的地址空间中。
Linux 中,如何实现共享内存:
int shm_open (....) ; // 通过 shm_open 系统调用,申请一片共享内存区。
void * mmap (.....) ; //通过 mmap 系统调用,将共享内存区映射到进程自己的地址空间。
基于存储区的共享:
操作系统在内存中划出一块共享存储区,数据的形式、存放位置都由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种高级通信方式。
基于数据结构的共享:
比如共享空间里只能放一个长度次10的数组。这种共享方式速度慢、限制多,是一种低级通信方式
4.2 消息传递
进程间的数据交换以格式化的消息(Message)为单位。进程通过操作系统提供的“发送消息/接收消息”两个原语进行数据交换。
消息传递:
①:直接通信方式——消息发送进程要指明接受进程的ID。
②:间接通信方式——通过 “信箱” 间接地通信。因此又称 “信箱通信方式”。
消息传递——直接通信方式
操作系统的内核中,包含着各个进程的PCB,进程的PCB中又包含了该进程的消息队列,就是其他进程给进程Q发送的这些消息,进程Q所接收的这些消息,都挂在进程Q的消息队列里面,进程P在给进程Q发送信息时,需要先在自己的地盘(地址空间)上完善消息的信息(消息头、消息体),接下来进程P使用发送原语,操作系统内核会接受并且放入进程Q的消息队列中,进程Q再使用接收原语,接收消息。
消息传递之~直接通信方式,点名道姓的消息传递。
消息传递——间接通信方式
进程P通过系统调用,申请一个邮箱,也可以申请多个邮箱,首先进程P要先在自己的地盘(地址空间)上完善消息的信息(消息头、消息体),进程P使用发送原语,指明要发送的哪个信箱(并没有指明发给哪个进程),进程Q使用接受原语,复制过来。
间接通信方式,以“信箱”作为中间实体进行消息传递。
可以多个进程往同一个信箱send消息,也可以多个进程从同一个信箱中receive消息。
4.3 管道通信
“管道”是一个特殊的共享文件,又名pipe文件。其实就是在内存中开辟一个大小固定的内,存缓冲区。
半双工通信:
全双工通信:
1.管道只能采用半双工通信,某一时间段内只能实现单向的传输。如果要实现双向同时通信,则需要设置两个管道。
2. 各进程要互斥地访问管道(由操作系统实现)
3. 当管道写满时,写进程将阻塞,直到读进程将管道中的数据取走,即可唤醒写进程。
4. 当管道读空时,读进程将阻塞,直到写进程往管道中写入数据,即可唤醒读进程。
5. 管道中的数据一旦被读出,就彻底消失。因此,当多个进程读同一个管道时,可能会错乱。对此,通常有两种解决方案:①一个管道允许多个写进程,一个读进程;②允许有多个写进程,多个读进程,但系统会让各个读进程轮流从管道中读数据(Linux 的方案)。
!注意:
写进程往管道写数据,即便管道没被写满,只要管道没空,读进程就可以从管道读数据。
读进程从管道读数据,即便管道没被读空,只要管道没满,写进程就可以往管道写数据。
小结:
以上便是本篇关于操作系统——进程 方面的相关内容,耗时较长制作不易,如果有帮到你,还请大家多多支持!!!后续还会为大家呈现更多优质内容,可以加个关注,防止走丢哦!