操作系统之旅--01(进程的描述与控制)

2019-07-14 11:46发布

1.进程的了解

   进程是程序的一次执行,他是一个程序及其数据在处理机上顺序执行时所发生的活动,它是系统进行资源分配和调度的一个独立单位。为了让参与并发执行的每个程序都能独立的运行,在操作系统中必须为之配置一个专门的数据结构,称为进程控制块PCB,系统用PCB来描述进程的基本情况和活动过程,进而控制和管理进程。这样有程序段,相关的数据段和PCB三部分便构成了进程实体。创建进程就是创建进程实体中的PCB,撤销进程实质上就是撤销进程控制块PCB。 那么什么是进程呢?操作系统中资源分配和独立运行的基本单位都是进程。 进程的基本状态: 1       就绪状态:进程已获得除CPU外的所有必要资源,只等待CPU时的状态。一个系统会将多个处于就绪状态的进程排成一个就绪队列。 2       执行状态:进程已获CPU,正在执行。单处理机系统中,处于执行状态的进程只一个;多处理机系统中,有多个处于执行状态的进程。 3       阻塞状态:正在执行的进程由于某种原因而暂时无法继续执行,便放弃处理机而处于暂停状态,即进程执行受阻。(这种状态又称等待状态或封锁状态) 通常导致进程阻塞的典型事件有:请求I/O,申请缓冲空间等。 一般,将处于阻塞状态的进程排成一个队列,有的系统还根据阻塞原因不同把这些阻塞集成排成多个队列。                                                  另外,在实际系统中,为管理需要,还存在着两种比较常见的状态:创建状态终止状态创建状态:此时,进程已经拥有了字节的PCB,但该进程所必需的资源或其它信息(如主存资源)尚未分配,进程自身还未进入主存,即创建工作尚未完成,进程还不能够被调度运行。 (创建进程的两个步骤: 为一个新进程创建PCB,并填写必要管理信息;把该进程转入就绪状态并插入就绪队列。) 终止状态:进程的终止首先要等待操作系统进行善后处理,然后将其PCB清零,并将PCB空间返还系统。 (当一个进程到达自然结束点或出现了无法克服的错误,或是被操作系统或其它有终止权的进程所终结,它将进入终止状态。进入终止状态的进程不能再执行,但在操作系统中依然保留一个记录,其中保存状态码和一些计时统计数据,供其它进程收集。一旦其它进程完成了对终止状态进程的信息提取之后,操作系统将删除该进程。                                           

2.进程控制块PCB的作用 

描述进程当前情况以及管理进程的全部信息,是操作系统中最重要的记录型数据结构。 使一个在多道程序的环境下不能独立运行的程序成为一个能独立运行的基本单位,一个能与其他进程并发执行的进程。
  1. 作为独立运行基本单位的标志.当系统创建一个新的进程,就为程序配备了一个PCB,就表示他有取得OS服务的权力,如打开文件系统中的文件,请求获得系统中的IO设备,当进程结束时又回收其PCB,进程也随之消亡,系统是通过PCB感知进程的存在。
  2. 实现间断性运行方式,多道环境下程序间断运行,程序必须保留自己运行时CPU现场信息。而这个信息是可以保存在PCB中的,当这个进程再次被调度的时候,他就可以靠PCB恢复CPU现场。
  3. 提供进程管理所需要的信息
比如说记录程序和数据在内存或外存中的始址指针,,这样就可以找到相应程序和数据。
  1. 提供进程调度所需要的信息,比如说此时进程的状态保存在PCB中,他是就绪状态才能被调用。
  2.  实现与其他进程的同步与通信,采用信号量机制时,每个进程中都有设置相应的用于同步的信号量,在PCB中还具有用于实现进程通信的区域或通信队列指针。
上面说完进程控制块的作用,下面说进程控制块的信息,它包含哪些信息呢?
  1. 进程标识符,标识进程的唯一性,分为内部标识和外部标识。
  2. 处理机状态,又称处理机上下文,主要由处理机的各种寄存器 组成
  3. 进程调度信息,包括进程状态,进程优先级等等
  4. 进程控制信息,包括一些程序清单,程序和数据地址等等。

3.操作系统内核两大功能

  1. 支撑功能
  1.1中断处理,如键盘命令输入,进程调度的时候,需要依赖中断处理   1.2时钟管理,如在时间片轮转调度中,时间片用完他就会产生一个中断信号   1.3原语操作,原语操作的过程是不可分割的基本单位,不允许被中断。是原子操作
  1. 资源管理功能
      进程管理,储存管理,设备管理等等

 4.进程控制

     进程的创建:      进程树:      子进程拥有父进程的所有资源,如继承父进程打开的文件,分配的缓冲区等等。父进程撤销,子进程会全部撤销,子进程撤销,资源会还给父进程。 但是在Windows中没有这种层级观念,是句柄的概念,句柄可以进程传递,获得句柄的进程就有控制其他进程的能力。 哪些事件可以创建一个进程?   用户登录,作业调度,提供服务,应用请求等等。 创建进程的过程:
  1. 申请空白PCB
  2. 分配资源,如内存,io,文件
  3. 初始化PCB
  4. 如果进程就绪队列能够插入新进程,则将其插入
进程终止过程:
  1. 根据进程的标识符拿到PCB,读取进程的状态。
  2. 如果实正在执行状态,则终止,调度标识符设为真,以便下次调度
  3. 如果有子孙进程也全部终止,并回收其所有的资源
  4. 将终止进程从所在对列中移除
进程的阻塞和唤醒:   比如请求资源失败,等待io操作等等会使进程阻塞,这是一种进程自身的主动行动。 而进程的唤醒则是被动的。

 5.进程同步

首先多个进程存在着制约的关系,有直接的也有间接的。 其次要明白临界资源这个概念,就是一次仅允许一个进程访问。 进程同步的例子,生产者-消费者,虽然两个进程可以以异步的方式运行,但是不允许消费者进程去空缓冲区拿数据,也不允许生产者进程向一个已装满产品的缓冲区投产品。 进程的公共变量必须要放到临界区,这样才能使所有的进程互斥访问,因为临界区一次只允许一个进程进入,并且一个进程不能无限停留在临界区,一个进程也不能无限等待进入临界区。 所以同步机制应遵循的规则: 空闲等待,忙则等待,有限等待(保证在有限时间内进入临界区),让权等待(当进程不能进入自己的临界区时让出cpu使用权) 工信号量机制:是一种卓有成效的进程同步具。
  1. 整型信号量
定义为一个用于表示资源数目的整形量S,他仅能通过两个原子操作wait(S)signal(S)来访问,即P,V操作。 p操作(wait):申请一个单位资源,进程进入        v操作(signal):释放一个单位资源,进程出来 wait(S){ While( S<=0); S--; } signal(S){ S++; }   2记录型信号量 整型信号量不符合“让权等待”原则。整型信号量的wait操作,当s 0时,当前进程会占着CPU不断测试;信号量原语不能被打断,这个占有CPU的进程会一直不断的占据CPU循环下去,陷入忙等。而纪录型信号量则不存在忙等。 3.AND型信号量 将进程在整个运行过程中的资源一次性全部分配,待用完后回收 4.信号量集 一般“信号量集”可以用于各种情况的资源分配和释放。下面是几种特殊的情况: 1)Swait(Sdd)表示每次申请d个资源,当资源数量少于d个时,便不予分配。 2)Swait(S11)表示互斥信号量。 3)Swait(S10)可作为一个可控开关(S1时,允许多个进程进入临界区;当S=0时禁止任何进程进入临界区) 由于一般信号量在使用时的灵活性,因此通常并不成对使用SwaitSsignal。为了避免死锁可一起申请所有需要的资源,但不一起释放。 信号量的应用:
  1. 利用信号量实现进程互斥
为使多个进程能互斥的访问某个临界资源,只需为该资源设置一互斥信号量mutex,并设其初始值为1,然后将各进程访问该资源的临界区CS置于wait(mutex)signal(mutex)操作之间即可。 semaphore S = 1; //初化信号量 P1 ( ) { // … P(S); // 准备开始访问临界资源,加锁 // 进程P1的临界区 V(S); // 访问结束,解锁 // … } P2() { // … P(S); //准备开始访问临界资源,加锁 // 进程P2的临界区; V(S); // 访问结束,解锁 // … }  需要注意的是在信号量机制实现进程互斥时应该注意,wait(mutex)signal(mutex)必须成对的出现。 2.利用信号量实现前趋关系 就是设有两个进程P1P2P1中有原语S1P2中有原语S2,希望在S1执行后再执行S2. 很简单,只需要P1P2进程共享一个变量S,并赋初值为0,将signal(S)操作放在语句S1后面,而在S2语句前面插入wait(S) 下面来一个复杂的: 信号量也可以用来描述程序之间或者语句之间的前驱关系。图2-8给出了一个前驱图,其中S1, S2, S3, , S6是最简单的程序段(只有一条语句)。为使各程序段能正确执行,应设置若干个初始值为“0”的信号量。例如,为保证S1 -> S2 S1 -> S3的前驱关系,应分别设置信号量a1a2。同样,为了保证 S2 -> S4S2 ->S5S3 -> S6S4 -> S6S5 -> S6,应设置信号量blb2cde                                                semaphore al=a2=bl=b2=c=d=e=0; //初始化信号量 S1() { // … V(al); V(a2) ; //S1已经运行完成 } S2() { P(a1); //检查S1是否运行完成 // … V(bl); V(b2); // S2已经运行完成 } S3() { P(a2); //检查S1是否已经运行完成 // … V(c); //S3已经运行完成 } S4() { P(b1); //检查S2是否已经运行完成 // … V(d); //S4已经运行完成 } S5() { P(b2); //检查S2是否已经运行完成 // … V(e); // S5已经运行完成 } S6() { P(c); //检查S3是否已经运行完成 P(d); //检查S4是否已经运行完成 P(e); //检查S5是否已经运行完成 // …; }       参考博客:https://www.cnblogs.com/Carrie-0173/p/6357742.html                  https://blog.csdn.net/qq_43291837/article/details/82865151