从操作系统层面细酌进程

133 阅读9分钟

进程

进程的定义

我们都知道,程序的本质,就是一个指令序列。

在早期的计算机里面,它只支持单道程序。

在一个程序运行的时候,他说,cpu是我的!内存是我的!I/O设备也是我的!

然后呢,他把程序段放在内存的低地址区域,把数据段放在高地址区域。

在引入多道程序技术之后,计算机就可以运行多个程序了。

这个时候,内存中就得放好多的程序段,好多的数据段!

此时,程序是并发的执行的,而操作系统的任务就是找到各个程序段,在内存的位置,找到对应的数据段。

所以,为了让操作系统能更好的去管理各个程序,让他们能并发的执行。引入了我们的主角——进程!

系统会为每个运行的程序配置一个数据结构,称为进程控制块(PCB),用来描述程序代码存放的位置

因此,PCB(Process Control Block),程序段,数据段,构成了进程的实体!

因此,我们平时所说的创建一个进程实际上是指,创建进程实体中的PCB,撤销进程实际上是撤销进程实体中的PCB

PCB是进程存在的唯一标志!PCB是进程的管理者,它记录了进程的信息, 进程控制和管理,资源的分配,处理机相关信息

对于进程,比较传统的定义有:

  1. 进程是程序的一次执行过程
  2. 进程是一个程序以及其数据在处理机上顺序执行所发生的活动。

讲的很多东西,都不是人话,总结下来就是,这些定义都在强调进程的一个特性——动态性

我们刚刚说了,程序段,数据段,构成了进程的实体。而进程实体是静态的。严格来讲,进程和进程实体不一样。进程是运行起来的进程实体,它是动态的!!

进程的组织

在一个系统中,通常会有上千个PCB,为了进行有效的管理,我们应该用适当的方式把PCB进行管理

进程的组织方式有两种:链接方式和索引方式。

链接方式

链接方式中有3种指针,指向进程的不同的状态。

  • 执行指针指向正在执行的进程
  • 就绪队列指针指向处于就绪态的进程(通常会有很多,优先级高的在前面)
  • 阻塞队列指针指向处于阻塞态的进程。

索引方式

链接的指向指的是队列。而索引的方式指的是索引。两者很类似。

唯一不同的是,索引表还会再指向不同的PCB

进程的特征

  • 动态性

    进程是程序的一次执行过程,是动态产生,变化,消亡的

  • 并发性

    内存中有多个进程实体,各个进程并发执行

  • 独立性

    进程是能独立运行,独立获得资源,接受调度的基本单位

  • 异步性

    之前我们说过,两个进程争夺一个资源的时候,无法确定抢到速度的快慢,因此它们是按照各自独立,不可预知的速度向前推进的。

  • 结构性

    每个进程都配置了一个PCB。结构上来看,都是PCB,程序段,数据段

重要考点

  • 定义:进程是进程实体的运行过程,是系统进行资源调度和分配的基本单位
  • PCB是进程存在的唯一标志,他是进程的管理者
  • 程序本身的运行所需要的数据在程序段和数据段
  • 动态性:进程最基本特征;独立性:进程是进行资源分配,调度的基本单位

进程的状态和切换

进程的状态——三种基本状态

分为运行态,就绪态,阻塞态。

  • 运行态占有CPU,并在CPU上面运行。
  • 就绪态具备了运行条件,但是没有空闲CPU,因此在等待(完事具备,只欠CPU)
  • 阻塞态因为在等待某个时间暂时不能运行

进程的状态——另外两种状态

我们都知道,一个程序运行的时候,会在内存中创建PCB,程序段,和数据段。

在这个创建的过程,我们就叫他创建态

在进程运行结束(或者遇到一些异常导致进程无法继续进行下去,比如i/0),需要撤销进程,比如回收内存区域,撤销I/O设备的权限

在这个撤销的过程,我们就叫他终止态

因此,进程有5种状态

进程的切换

我们通过一张图,来总体的看一下各个状态的转换。

在创建态完成之后,系统已经做好了准备工作。比如PCB的创建

随机它进入了就绪态,就绪态他拥有了除了处理机以外的其他权限。

随后由于上一个进程的时间片到了,进程被CPU调度,它拥有了处理机的权限!

于是,她就想用系统调用的方式,进入核心态,获得打印机的资源。于是,他就进入了漫长的等待,也就是阻塞态。阻塞状态下,他失去了处理机和其他资源的权限。

等完了以后,申请的资源被重新分配回来了,它又回到了就绪态,此时它又拥有了除了处理机以外的其他权限。

然后它被调度,进入运行态。

程序运行结束了,或者遇到异常了,它进入终止态,从cpu中回收资源,撤销PCB

我们发现,从运行态到阻塞态,是主动申请资源的过程,是主动的

而从阻塞态到就绪态,是等待资源响应的过程,是被动的

进程的控制

基本概念

进程控制简单理解,就是实现刚刚说的5种进程状态的转换

如何实现?

我们知道,操作系统会将很多PCB挂到相应状态的队列当中。

  • 创建态——>就绪态

    需要修改PCB内容进入就绪队列。

  • 就绪态——>运行态

    需要恢复程序运行环境(之前可能没执行完,没到终止态),修改PCB内容和相应队列

  • 运行态——>就绪态

    这是进程切换了,比如进程3切换到进程1,需要修改PCB内容,将他放进阻塞队列

  • 阻塞态——>就绪态

    需要修改PCB内容,将他放进就绪队列。如果等待资源,还需要给进程分配系统资源

  • 运行态——>终止态

    回收资源,撤销PCB

思考一个问题,如果说一个进程将它从一个队列改为另一个队列,但是系统没有改PCB里面的状态标志(PCB的内容)。

这种情况很危险,有可能导致系统错误!!

为了防止这个问题,采用了原语

什么是原语?

原语的特点就是不允许中断,一气喝成。

学过多线程的同学也知道,这其实是原子操作

那原语的本质又是啥呢?

原语采用“开中断”,“关中断”指令实现。

在“开中断”,“关中断”之前的操作,不会被外部中断信号打断。

既然它这么牛,其实我们也可以想到,这是操作系统在核心态中执行的特权指令。

既然说到特权指令,那我们不得不再复习一下操作系统的内核了。

操作系统内核:时钟管理,中断管理,原语,对系统资源的管理(进程管理,存储器管理,设备管理)

进程相关的原语

本质:进程控制会导致进程状态的转换。无论哪个原语,要做的无非3件事情:

1.更新PCB信息(如修改进程状态标志,将运行环境保存到PCB,从PCB中恢复运行环境)

  • 所有的进程控制原语就一定会修改进程状态标识
  • 剥夺当前运行的CPU之前,就一定得保存其运行环境
  • 某进程开始运行前,需要恢复运行期环境

2.将PCB插入合适队列

3.分配/回收资源

进程通信

什么是进程通信?

顾名思义,其实进程通信就是指进程之间的信息交换

进程是系统分配资源的单位,因此各进程拥有的内存地址空间相互独立。

为了保证安全,一个进程不能直接访问另一个进程的地址空间。

但是进程之间的信息交换又是必须实现的,为了保障进程间的通信,操作系统提供了一些方法

进程通信——共享存储

我们可以再内存中设置一个共享空间。供两个进程来访问。

这两个进程对共享空间的访问必须是互斥的。

进程通信——管道通信

管道是用于连续读写进程的一个共享文件,其实就是再内存中开辟一个大小固定的缓冲区

但由于上图,我们发现,管道只能采用半双工通信,某一时间段只能实现单向的传输。但如果实现双向同时通信,则需要设置两个管道。

各个进程对于管道的访问也是需要互斥的进行的

管道通信的具体流程:进程1 往管道内部写入数据,当管道写满的时候,写进程的write()系统调用将会被阻塞,等待读进程将数据取走。当都进程将数据全部取走以后,此时读进程的read()系统调用将会被阻塞。

注意:如果没有写满,不允许读。如果没有读完,不允许写;

并且数据一旦读出,就从管道内被抛弃了。这意味着读进程最多只能有一个,否则会有读错的情况

进程通信——消息传递

进程间的数据交换以格式化的消息,(Message)为单位。进程通过操作系统提供的 “发送消息/接受消息”两个原语进行数据的交换。

一个Message包括消息头和消息体。消息头里面包括进程ID,接受进程id,信息类型,消息长度等格式化信息。

而消息传递有分为两种方式——直接通信,间接通信。

  • 直接通信就是将Message挂载到接受消息的进程当中,形成一个队列。
  • 间接通信就是在俩进程之间设置一个信箱。从中寄出或者取走信息。(有点像公共存储区域)

重要考点

  1. 共享存储需要互斥的访问空间
  2. 一个管道只能实现半双工通信(单向)
  3. 管道通信写满不写,读空不读;没写满不读,没读空不写
  4. 消息传递的两种方式