进程与程序的区别
程序:静态的,就是存放在磁盘里的可执行文件,就是一系列的指令集合。
进程:是动态的,是程序的一次执行过程;同一程序多次执行会对应多个进程;比如你使用QQ同时登陆多个账号,每一个账号就是一个进程。
如何进行区分这些进程呢?
当进程被创建时,操作系统会为该进程分配唯一的、不重复的进程ID号。(PID)
操作系统记录信息:
记录PID、进程所属用户(UID),可以让操作系统区分各个进程;
记录给进程分配了哪些资源(如:分配多少内存、正在使用哪些I\O设备、正在使用哪些文件),可用于实现操作系统对资源的管理;
记录进程的运行情况(如:CPU使用时间、磁盘使用情况、网络流量情况等),可用于实现操作系统对线程的控制、调度
这这些信息全部被放在一个数据结构PCB中,即进程控制块;操作系统需要对各个并发运行的进程进行管理,但凡管理时所需要的信息,都会放在PCB中
进程当前的状态:就绪态、阻塞态、运行态
进程的组成
PCB:进程描述信息;进程控制与管理信息;资源分配清单;处理机相关信息
程序段:程序的代码(指令序列)
数据段:运行过程中产生的各种数据(如:程序中定义的变量)
注意:其中PCB是给操作系统用的;程序段、数据段是给进程自己用的。
一个程序是如何运行的?

进程就是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位(其中进程实体就是程序在运行过程中,某一状态的改变,比如上述:x++;x=2)。
一个进程被调度,就是指操作系统决定让这个进程上CPU运行。
注意:同时挂起三个QQ号,会对应三个QQ进程进程,他们的PCB、数据段各不相同(不同的用户信息等),但是程序段内容都是相同的(都是运行着相同的QQ程序)。
进程相比于程序的特性:
动态性:进程最基本的特性;进程是程序的一次执行过程,是动态地产生、变化和消亡;
并发性:内存中有多个进程实体,各进程可并发执行;
独立性:进程是能独立运行、独立获得资源、独立接受调度的基本单位;
异步性:各进程按各自独立的、不可预知的速度向前推进,操作系统要提供“进程同步机制”来解决异步问题(注意:异步性会导致并发程序执行结果的不确定性)
结构性:每个进程都会配置一个PCB。结构上,进程是由程序段、数据段、PCB组成的。
进程的状态和转换:

系统中可能会有很多个进程处于就绪态;当CPU空闲的时候,操作系统就会选择一个就绪进程,让他上CPU运行;
如果一个进程此时在CPU上运行,此进程处于“运行态”,CPU会执行该进程对应的程序(执行指令程序);
在进程运行过程中,可能会请求等待某个事件的发生(如等待某种系统资源的分配,或者等待其它进程的响应)。在这个事件发生之前,进程无法继续进行往下执行,此时操作系统会让这个进程下CPU(不可能一直让他占有CPU资源),并让他进入“阻塞态”;
当CPU空闲时,又会选择另一个“就绪态”进程上CPU运行;
一个进程可以执行exit系统调用,请求操作系统终止该进程。此时该进程会进入“终止态”,操作系统会让该进程下CPU,并回收内存空间资源,最后还要回收该进程的PCB;
终止完成后,进程结束。
进程状态转换

运行态->阻塞态是一种进程自身做出的主动行为;
阻塞态->就绪态不是进程自身能控制的,是一种被动行为。
注意: 不能由阻塞态直接转换为运行态,也不能由就绪态直接转换为阻塞态(因为进入阻塞态是进程主动请求的,必然需要进程在运行时才能发出这种请求)
其中运行态装换为就绪态:
时间片到:CPU收到一个时钟中断的信号,发现该进程已经运行很长一段时间了,不应该让其再运行了,这时就要被剥夺CPU资源。
基本状态:就绪、运行、阻塞
单CPU情况下,同一时刻一个进程处于运行态;多CPU多个。
进程PCB中,会有一个变量state来表示进程的当前状态。
如何实现进程控制
进程控制需要一气呵成,假设PCB中的变量state表示进程当前所处的状态,1表示就绪态,2表示诸阻塞态

假设进程2等待的某个事件已经发生了,那么控制进程的内核程序主要做两件事:
1.将PCB2的state置为1;
2.将PCB2从阻塞队列放到就绪队列中。
注意:如果在完成第一步之后,收到了中断信号,那么此时PCB2任然在阻塞队列中,但是其state=1,导致操作系统某些关键数据结构不统一的情况;所以转换要“一气呵成”。
“原语”的执行具有原子性,即执行过程只能一气呵成,期间不允许被中断;可以使用“关中断指令”和“开中断”指令这两个特权指令实现原子性;CPU执行力关中断指令之后,就不再检查中断信号,直到执行开中断指令之后才会恢复。这样,关中断、开中断之间的这些指令就是不可被中断的。
进程的创建
创建原语:申请空白PCB;为新进程分配所需资源;初始化PCB(PID,UID);将PCB插入就绪队列(创建态->就绪态)
引起进程创建的事件:
1.用户登录:分时系统中,用户登录成功,系统会建立为其建立一个新进程(比如:QQ登录)
2.作业调度:多道批处理系统中,有新作业放入内存中,会为其建立;(就是从外存中挑选一个程序放入到CPU中,使其运行)
3.提供服务:用户向操作系统提出某些请求;
4.应用请求:由用户主动请求创建一个子进程。
进程终止
撤销原语:从PCB集合中找到终止进程的PCB;若进程正在运行,立即剥夺CPU,将CPU分配给其它进程;终止其所有子进程;将该进程拥有的所有资源归还给父进程或操作系统,删除PCB
引起进程终止的事件:
1.正常结束(exit系统调用);
2.异常结束:整数除以0;非法使用特权指令,然后被操作系统强行杀掉
3.外界干预:用户选择执行一个指令杀掉进程
进程的阻塞和唤醒
进程阻塞
阻塞原语:找到阻塞进程对应的PCB;保护进程运行现场,将PCB状态信息设置为“阻塞态”,暂时停止进程运行;将PCB插入相应事件的等待队列(运行态->阻塞态)
引起进程阻塞的事件:需要等待系统分配某种资源;需要等待相互合作的其它进程完成工作
进程唤醒
唤醒原语:在事件等待队列中找到PCB;将PCB从等待队列移除,设置进程为就绪态;将PCB插入到就绪队列,等待被调度
引起进程唤醒的事件:等待事件发生(因何阻塞,因何唤醒)(阻塞->就绪)
进程的切换(运行->就绪,就绪->运行)
切换原语:将运行环境信息存入PCB;PCB移入相应队列;选择另一个进程执行,并更新其PCB;根据PCB恢复新进程所需的运行环境
引起进程切换的事件:
1.当前进程时间片刻(就是进程运行时间太长了)
2.有更高优先级的进程到达
3.当前进程主动阻塞
4.当前进程终止
注意:其中的运行环境信息
CPU中会设置很多“寄存器”,用来存放程序运行过程中所需要的某些数据。
PSW:程序状态字寄存器(进程是就绪态、运行态...)
PC:程序计数器,存放下一条指令的地址
IR:指令寄存器,存放当前正在执行的指令
通用寄存器:其它一些必要的信息
这里注意另一个进程在运行过程中,也需要使用各种寄存器,那么前一个进程的信息就直接丢失了吗?
不会,在进程切换时先在PCB中保存这个进程的运行环境(保存一些必要的寄存器信息,比如:PSW,PC,通用寄存器);当原来的进程再次投入运行时,通过PCB恢复之前的运行环境
无论时哪个进程控制原语,要做的无非三类事情
1.更新PCB中的信息(修改进程状态,保存\恢复运行环境);
2.将PCB插入合适的队列;
3.分配/回收资源
进程间通信
进程间通信是指两个进程之间产生数据交互
进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立。(一个进程不能访问其它进程的内存地址空间,比如:你下载一个APP,如果他可以访问你的微信,直接将你的私密信息拿走了)
所以,进程间不能直接进行相互访问,要通过操作系统
共享内存
一个进程申请一块共享内存,其它进程也可以进行访问;但是注意各个进程对共享内存的访问应该是互斥的(一个进程在访问时,其它进程应该等待)
基于数据共享:比如共享空间里只能放一个长度为10的数组。速度慢、限制多,低级通信。
基于存储区共享:操作系统在内存中划出一块内存共享区,数据形式、存放位置由通信进程决定。速度快。
消息队列(传递)
进程间的数据交换以格式化的消息为单位。进程通过操作系统提供的“发送消息\接受消息”两个原语进行数据交换。
消息头(发送进程ID、接受进程ID、消息长度等格式化信息)+消息体(一个进程传输给另一个进程的数据)
直接通信方式
消息发送进程要指明接收进程的ID
操作系统的内核中,管理着各个进程的PCB;在各个进程PCB中包含着一个消息队列;其它进程要给该进程发送消息,要被该进程接收的消息,都是存放在该进程的消息队列中
比如:如果进程P,要给Q发送消息,使用原语(send(Q,msg)),先给操作系统,操作系统再将msg放在Q的PCB消息队列中;在接收到消息之后,进程Q会使用接收原语receive(p,&msg),操作系统会从进程Q的消息队列中找到消息msg,将msg复制到进程Q的地址空间中。

间接通信方式
通过“信箱”间接地通信。
比如:进程P要与进程Q进行通信,进程P先向操作系统申请一个邮箱或者多个邮箱,进程P使用原语send(A,msg),进程Q使用原语receive(A,&msg)从信箱A中接收这个消息;可以多个进程同时向一个信箱发送消息,也可以多个同个进程同时从一个邮箱接收消息。

管道通信
可以将其就想象成我们平时看到的“水管”,水管的水流只能由一边到另一边,不能是双向,那么管道之间的数据传输也就是单向传递的
“管道”是一个特殊的共享文件。其实就是在内存中开辟一个大小固定的内存缓冲区(进程就可以向该管道中写数据和读数据);具有先进先出的特性(可以理解为循环队列)
注意管道与共享内存的区别:
管道的数据具有先进先出的特性,先写入的数据,其它进程如果要读数据,只能将先写入的数据拿走;而共享内存就是可以从任意位置读取数据
总结:
1.管道只能采用半双工通信,某一段时间内只能实现单向传输。要实现双向,设置两个管道;
2.各个进程要互斥访问管道(操作系统实现);
3.当管道写满时,写进程将阻塞,直到读进程将管道中数据取走,即可唤醒写进程;
4.当管道读空时,读进程将阻塞,直到写进程往管道中写入数据,即可唤醒写进程;
5.管道中的数据一旦被读出,就彻底消失。因此,多个进程读同一管道时,可能错乱。解决方案:允许多个写进程,多个读进程,但系统会让各个读进程轮流从管道中读数据。(Linux)
注意:只要管道没满或者没空;进程就能向管道写或读数据。
2万+

被折叠的 条评论
为什么被折叠?



