汤子瀛 操作系统整理[2]——第二章 进程管理

 

第二章  进程管理

进程的基本概念

进程的三种基本状态:就绪(Ready)状态、执行状态、阻塞状态;

 

 

 

 

 

 

 

 


具有挂起状态的进程状态图

引入挂起状态的原因:①终端用户的请求;②父进程请求;③负荷调节的需要;④操作系统的需要。

 

 

 

 

 

 

 

 

 

 

 


进程控制块

1. 进程控制块的作用:使一个在多道程序环境下不能独立运行的程序(含数据),成为一个能独立运行的基本单位,一个能与其它进程并发执行的进程。或者说,OS是根据PCB来对并发执行的进程进行控制和管理的。

2. 进程控制块中的信息:

1) 进程标识符:进程标识符用于惟一地标识一个进程。一个进程通常有两种标识符:

    ①内部标识符。在所有的操作系统中,都为每一个进程赋予一个惟一的数字标识符,它通常是一个进程的序号。设置内部标识符主要是为了方便系统使用。

    ②外部标识符。它由创建者提供,通常是由字母、数字组成,往往是由用户(进程)在访问该进程时使用。为了描述进程的家族关系, 还应设置父进程标识及子进程标识。此外,还可设置用户标识,以指示拥有该进程的用户。

    2) 处理机状态:处理机状态信息主要是由处理机的各种寄存器中的内容组成的。

        ①通用寄存器,又称为用户可视寄存器,它们是用户程序可以访问的,用于暂存信息;

        ②指令计数器,其中存放了要访问的下一条指令的地址;

        ③程序状态字PSW,其中含有状态信息,如条件码、执行方式、 中断屏蔽标志等;

        ④用户栈指针,指每个用户进程都有一个或若干个与之相关的系统栈,用于存放过程和系统调用参数及调用地址。栈指针指向该栈的栈顶。

    3) 进程调度信息:存放一些与进程调度和进程对换有关的信息,包括:

        ①进程状态,指明进程的当前状态,作为进程调度和对换时的依据;

        ②进程优先级,描述进程使用处理机的优先级别的一个整数,优先级高的进程应优先获得处理机;

        ③进程调度所需的其它信息,它们与所采用的进程调度算法有关,比如,进程已等待CPU的时间总和、 进程已执行的时间总和等;

        ④事件,是指进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因。

    4) 进程控制信息:进程控制信息包括:

        ①程序和数据的地址,是指进程的程序和数据所在的内存或外存地(首)址,以便再调度到该进程执行时,能从PCB中找到其程序和数据;

        ②进程同步和通信机制,指实现进程同步和进程通信时必需的机制,如消息队列指针、信号量等,它们可能全部或部分地放在PCB中;

        ③资源清单,是一张列出了除CPU以外的、进程所需的全部资源及已分配到该进程的资源的清单;

        ④链接指针,它给出了本进程(PCB)所在队列中的下一个进程的PCB的首地址。

 

进程控制

进程的创建

引起创建进程的事件:用户登录、作业调度、提供服务、应用请求;

进程的创建(Creation of Progress):

    (1)申请空白PCB。

   (2)为新进程分配资源。

    (3)初始化进程控制块。

    (4)将新进程插入就绪队列,如果进程就绪队列能够接纳新进程, 便将新进程插入就绪队列。

 

进程的终止

引起进程终止(Termination of Process)的事件:正常结束、异常结束、外界干预;

进程的终止过程:

    (1)根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读出该进程的状态。

   (2)若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真,用于指示该进程被终止后应重新进行调度。

    (3)若该进程还有子孙进程,还应将其所有子孙进程予以终止,以防他们成为不可控的进程。

    (4)将被终止进程所拥有的全部资源,或者归还给其父进程,或者归还给系统。

    (5)将被终止进程(它的PCB)从所在队列(或链表)中移出,等待其他程序来搜集信息。

进程的阻塞与唤醒

引起进程阻塞和唤醒的事件: 请求系统服务、启动某种操作、新数据尚未到达、无新工作可做;

进程阻塞过程:

    (1)正在执行的进程,当发现上述某事件时,由于无法继续执行,于是进程便通过调用阻塞原语block把自己阻塞。可见,进程的阻塞是进程自身的一种主动行为。

    (2)进入block过程后,由于此时该进程还处于执行状态,所以应先立即停止执行,把进程控制块中的现行状态由“执行”改为阻塞,并将PCB插入阻塞队列。如果系统中设置了因不同事件而阻塞的多个阻塞队列,则应将本进程插入到具有相同事件的阻塞(等待)队列。

    (3)最后,转调度程序进行重新调度,将处理机分配给另一就绪进程,并进行切换,亦即,保留被阻塞进程的处理机状态(在PCB中),再按新进程的PCB中的处理机状态设置CPU的环境。

进程唤醒过程:当被阻塞进程所期待的事件出现时,如I/O完成或其所期待的数据已经到达,则由有关进程(比如,用完并释放了该I/O设备的进程)调用唤醒原语wakeup( ),将等待该事件的进程唤醒。唤醒原语执行的过程是:首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后再将该PCB插入到就绪队列中

 

进程的挂起与激活

进程的挂起:当出现了引起进程挂起的事件时,比如,用户进程请求将自己挂起,或父进程请求将自己的某个子进程挂起,系统将利用挂起原语suspend( )将指定进程或处于阻塞状态的进程挂起。挂起原语的执行过程是:首先检查被挂起进程的状态,若处于活动就绪状态,便将其改为静止就绪;对于活动阻塞状态的进程,则将之改为静止阻塞。为了方便用户或父进程考查该进程的运行情况而把该进程的PCB复制到某指定的内存区域。最后,若被挂起的进程正在执行,则转向调度程序重新调度。

进程的激活过程:当发生激活进程的事件时,例如,父进程或用户进程请求激活指定进程,若该进程驻留在外存而内存中已有足够的空间时,则可将在外存上处于静止就绪状态的进程换入内存。这时,系统将利用激活原语active( )将指定进程激活。激活原语先将进程从外存调入内存,检查该进程的现行状态,若是静止就绪,便将之改为活动就绪;若为静止阻塞便将之改为活动阻塞。假如采用的是抢占调度策略,则每当有新进程进入就绪队列时,应检查是否要进行重新调度,即由调度程序将被激活进程与当前进程进行优先级的比较,如果被激活进程的优先级更低,就不必重新调度;否则,立即剥夺当前进程的运行,把处理机分配给刚被激活的进程。

 

进程同步

进程同步的基本概念

可把一个访问临界资源的循环进程描述如下:

repeat

    entry section

    critical section;

    exit section

    remainder section;

until false;

同步机制应遵循的规则:空闲让进、忙则等待、有限等待、让权等待。 

 

信号量机制

1.整型信号量

除初始化外,仅能通过两个标准的原子操作(Atomic Operation) wait(S)和signal(S)来访问。这两个操作一直被分别称为P、V操作。 wait和signal操作可描述为:

        wait(S):    while S≤0 do no-op

                    S∶=S-1;

        signal(S): S∶=S+1;

在整型信号量机制中的wait操作,只要是信号量S≤0, 就会不断地测试。因此,该机制并未遵循“让权等待”的准则, 而是使进程处于“忙等”的状态。

 

2.记录型信号量

记录型信号量机制,是一种不存在“忙等”现象的进程同步机制。但在采取了“让权等待”的策略后,又会出现多个进程等待访问同一临界资源的情况。为此,在信号量机制中,除了需要一个用于代表资源数目的整型变量value外,还应增加一个进程链表L,用于链接上述的所有等待进程。记录型信号量是由于它采用了记录型的数据结构而得名的。它所包含的上述两个数据项可描述为:

type semaphore=record

         value:integer;

         L:list of process;

         end

相应地,wait(S)和signal(S)操作可描述为:

procedure wait(S)

     var S: semaphore;

     begin

       S.value∶ =S.value-1;

       if S.value<0 then block(S,L)

     end

procedure signal(S)

     var S: semaphore;

     begin

      S.value∶ =S.value+1;

      if S.value≤0 then wakeup(S,L);

     end

S.value的初值表示系统中某类资源的数目, 因而又称为资源信号量,对它的每次wait操作,意味着进程请求一个单位的该类资源,因此描述为S.value∶=S.value-1; 当S.value<0时,表示该类资源已分配完毕,因此进程应调用block原语,进行自我阻塞,放弃处理机,并插入到信号量链表S.L中。可见,该机制遵循了“让权等待”准则。此时S.value的绝对值表示在该信号量链表中已阻塞进程的数目。 对信号量的每次signal操作,表示执行进程释放一个单位资源,故S.value∶=S.value+1操作表示资源数目加1。 若加1后仍是S.value≤0,则表示在该信号量链表中,仍有等待该资源的进程被阻塞,故还应调用wakeup原语,将S.L链表中的第一个等待进程唤醒。如果S.value的初值为1,表示只允许一个进程访问临界资源,此时的信号量转化为互斥信号量。

 

3.AND型信号量

将进程在整个运行过程中需要的所有资源,一次性全部地分配给进程,待进程使用完后再一起释放。只要尚有一个资源未能分配给进程,其它所有可能为之分配的资源,也不分配给他。亦即,对若干个临界资源的分配,采取原子操作方式:要么全部分配到进程,要么一个也不分配。由死锁理论可知,这样就可避免上述死锁情况的发生。为此,在wait操作中,增加了一个“AND”条件,故称为AND同步,或称为同时wait操作, 即Swait(Simultaneous wait)定义如下:

Swait(S1, S2, …, Sn)

    if Si≥1 and … and Sn≥1 then

        for i∶ =1 to n do

        Si∶=Si-1;

        endfor

    else

     place the process in the waiting queue associated with the first Si found   with Si<1, and set the program count of this process to the beginning of Swait operation

    endif

Ssignal(S1, S2, …, Sn)

      for i∶ =1 to n do

      Si=Si+1;

      Remove all the process waiting in the queue associated with Si into the ready queue.

  endfor;

 

4.信号量集

Swait(S1, t1, d1, …, Sn, tn, dn)

    if Si≥t1 and … and Sn≥tn then

      for i∶=1 to n do

        Si∶=Si-di;

    endfor

   else

   Place the executing process in the waiting queue of the first Si with Si<ti and set its program counter to the beginning of the Swait Operation. 

   endif

   signal(S1, d1, …, Sn, dn)

   for i∶=1 to n do

     Si ∶=Si+di;

Remove all the process waiting in the queue associated with Si into the ready queue

   endfor;

一般“信号量集”的几种特殊情况:

(1) Swait(S, d, d)。 此时在信号量集中只有一个信号量S, 但允许它每次申请d个资源,当现有资源数少于d时,不予分配。

(2) Swait(S, 1, 1)。 此时的信号量集已蜕化为一般的记录型信号量(S>1时)或互斥信号量(S=1时)。(3) Swait(S, 1, 0)。这是一种很特殊且很有用的信号量操作。当S≥1时,允许多个进程进入某特定区;当S变为0后,将阻止任何进程进入特定区。换言之,它相当于一个可控开关。

 

信号量的应用

1. 利用信号量实现进程互斥

利用信号量实现进程互斥的进程可描述如下:

Var mutex:semaphore∶   =1;

    begin

    parbegin

     process 1: begin

                repeat

                    wait(mutex);

                    critical section

                    signal(mutex);

                    remainder seetion

                until false;

              end

     process 2: begin

                    repeat

                        wait(mutex);

                        critical section

                        signal(mutex);

                         remainder section

                   until false;

                   end

    parend

 

2. 利用信号量实现前趋关系

 

 

 

 

 

 

 

 


Var a,b,c,d,e,f,g; semaphore∶=0,0,0,0,0,0,0;

      begin

        parbegin

        begin S1; signal(a); signal(b); end;

        begin wait(a); S2; signal(c); signal(d); end;

        begin wait(b); S3; signal(e); end;

        begin wait(c); S4; signal(f); end;

        begin wait(d); S5; signal(g); end;

        begin wait(e); wait(f); wait(g); S6; end;

        parend

   end

 

管程机制

一个管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据;

管程由三部分组成:① 局部于管程的共享变量说明;② 对该数据结构进行操作的一组过程;③ 对局部于管程的数据设置初始值的语句。此外,还须为管程赋予一个名字。

 

进程通信

进程通信的类型

1. 共享存储器系统(Shared-Memory System)

(1)基于共享数据结构的通信方式。

    (2)基于共享存储区的通信方式。

2. 消息传递系统(Message passing system)

进程间的数据交换,是以格式化的消息(message)为单位的;在计算机网络中,又把message称为报文。

3. 管道(Pipe)通信

“管道”,是指用于连接一个读进程和一个写进程以实现他们之间通信的一个共享文件,又名pipe文件。向管道(共享文件)提供输入的发送进程(即写进程), 以字符流形式将大量的数据送入管道;而接受管道输出的接收进程(即读进程),则从管道中接收(读)数据。

为了协调双方的通信,管道机制必须提供以下三方面的协调能力:

    ① 互斥,即当一个进程正在对pipe执行读/写操作时,其它(另一)进程必须等待。

    ② 同步,指当写(输入)进程把一定数量(如4 KB)的数据写入pipe,便去睡眠等待, 直到读(输出)进程取走数据后,再把他唤醒。当读进程读一空pipe时,也应睡眠等待,直至写进程将数据写入管道后,才将之唤醒。

    ③ 确定对方是否存在,只有确定了对方已存在时,才能进行通信。

 

消息传递通信的实现方法

1. 直接通信方式

指发送进程利用OS所提供的发送命令,直接把消息发送给目标进程。此时,要求发送进程和接收进程都以显式方式提供对方的标识符。通常,系统提供下述两条通信命令(原语):

         Send(Receiver, message); 发送一个消息给接收进程;

         Receive(Sender, message); 接收Sender发来的消息;

在某些情况下,接收进程可与多个发送进程通信,因此,它不可能事先指定发送进程。例如,用于提供打印服务的进程,它可以接收来自任何一个进程的“打印请求”消息。对于这样的应用,在接收进程接收消息的原语中的源进程参数,是完成通信后的返回值,接收原语可表示为:

         Receive (id, message); 

 

2. 间接通信方式

    (1) 信箱的创建和撤消。进程可利用信箱创建原语来建立一个新信箱。创建者进程应给出信箱名字、信箱属性(公用、私用或共享);对于共享信箱, 还应给出共享者的名字。当进程不再需要读信箱时,可用信箱撤消原语将之撤消。

    (2) 消息的发送和接收。当进程之间要利用信箱进行通信时,必须使用共享信箱,并利用系统提供的下述通信原语进行通信。

         Send(mailbox, message); 将一个消息发送到指定信箱;

         Receive(mailbox, message); 从指定信箱中接收一个消息;

信箱可由操作系统创建,也可由用户进程创建,创建者是信箱的拥有者。

 

消息缓冲队列通信机制

1. 消息缓冲队列通信机制中的数据结构

    (1) 消息缓冲区。在消息缓冲队列通信方式中,主要利用的数据结构是消息缓冲区。它可描述如下:

        type message buffer=record

            sender; 发送者进程标识符

            size; 消息长度

           text; 消息正文

            next; 指向下一个消息缓冲区的指针

         end

 

    (2) PCB中有关通信的数据项。在利用消息缓冲队列通信机制时,在设置消息缓冲队列的同时,还应增加用于对消息队列进行操作和实现同步的信号量,并将它们置入进程的PCB中。在PCB中应增加的数据项可描述如下:                    

        type processcontrol block=record

            …

            mq; 消息队列队首指针

            mutex; 消息队列互斥信号量

            sm; 消息队列资源信号量

            …

        end

 

2. 发送原语

发送进程在利用发送原语发送消息之前,应先在自己的内存空间,设置一发送区a,见图 2 - 12 所示,把待发送的消息正文、发送进程标识符、消息长度等信息填入其中,然后调用发送原语,把消息发送给目标(接收)进程。发送原语首先根据发送区a中所设置的消息长度a.size来申请一缓冲区i,接着,把发送区a中的信息复制到缓冲区i中。为了能将i挂在接收进程的消息队列mq上,应先获得接收进程的内部标识符j,然后将i挂在j.mq上。由于该队列属于临界资源, 故在执行insert操作的前后,都要执行wait和signal操作。

procedure send(receiver, a)

     begin

        getbuf(a.size,i);                         根据a.size申请缓冲区;

        i.sender∶   =a.sender;  将发送区a中的信息复制到消息缓冲区之中;

        i.size∶   =a.size;

        i.text∶   =a.text;

        i.next∶   =0;

       getid(PCB set, receiver.j);   获得接收进程内部标识符;

       wait(j.mutex);

       insert(j.mq, i);   将消息缓冲区插入消息队列;

       signal(j.mutex);

       signal(j.sm);

    end

 

3. 接收原语

接收原语描述如下:

procedure receive(b)

   begin

    j∶   =internal name; j为接收进程内部的标识符;

    wait(j.sm);

    wait(j.mutex);

    remove(j.mq, i); 将消息队列中第一个消息移出;

    signal(j.mutex);

    b.sender∶   =i.sender; 将消息缓冲区i中的信息复制到接收区b;

    b.size∶   =i.size;

    b.text∶   =i.text;

  end

 

线程

线程的属性

①轻型实体。

    ②独立调度和分派的基本单位。

    ③可并发执行。

    ④共享进程资源。

 

线程的状态

(1) 状态参数

    ① 寄存器状态,它包括程序计数器PC和堆栈指针中的内容;

    ② 堆栈, 在堆栈中通常保存有局部变量和返回地址;

    ③ 线程运行状态,用于描述线程正处于何种运行状态;

    ④ 优先级,描述线程执行的优先程度;

    ⑤ 线程专有存储器,用于保存线程自己的局部变量拷贝;

    ⑥ 信号屏蔽,即对某些信号加以屏蔽。

(2) 线程运行状态。

如同传统的进程一样,在各线程之间也存在着共享资源和相互合作的制约关系,致使线程在运行时也具有间断性。相应地,线程在运行时,也具有下述三种基本状态:

① 执行状态,表示线程正获得处理机而运行;

② 就绪状态, 指线程已具备了各种执行条件,一旦获得CPU便可执行的状态;

③ 阻塞状态,指线程在执行中因某事件而受阻,处于暂停执行时的状态。

 

线程的创建和终止

在多线程OS环境下,应用程序在启动时,通常仅有一个线程在执行,该线程被人们称为“初始化线程”。它可根据需要再去创建若干个线程。在创建新线程时,需要利用一个线程创建函数(或系统调用),并提供相应的参数,如指向线程主程序的入口指针、堆栈的大小,以及用于调度的优先级等。在线程创建函数执行完后,将返回一个线程标识符供以后使用。

终止线程的方式有两种:一种是在线程完成了自己的工作后自愿退出;另一种是线程在运行中出现错误或由于某种原因而被其它线程强行终止。

 

多线程OS中的进程

在多线程OS中,进程是作为拥有系统资源的基本单位,通常的进程都包含多个线程并为它们提供资源,但此时的进程就不再作为一个执行的实体。多线程OS中的进程有以下属性:

    (1) 作为系统资源分配的单位。

    (2) 可包括多个线程。

    (3) 进程不是一个可执行的实体。

 

线程间的同步和通信

互斥锁(mutex)

互斥锁是一种比较简单的、用于实现进程间对资源互斥访问的机制。由于操作互斥锁的时间和空间开锁都较低, 因而较适合于高频度使用的关键共享数据和程序段。

互斥锁可以有两种状态, 即开锁(unlock)和关锁(lock)状态。 相应地,可用两条命令(函数)对互斥锁进行操作。其中的关锁lock操作用于将mutex关上,开锁操作unlock则用于打开mutex。

 

条件变量

每一个条件变量通常都与一个互斥锁一起使用,亦即,在创建一个互斥锁时便联系着一个条件变量。单纯的互斥锁用于短期锁定,主要是用来保证对临界区的互斥进入。而条件变量则用于线程的长期等待,直至所等待的资源成为可用的。

线程首先对mutex执行关锁操作,若成功便进入临界区,然后查找用于描述资源状态的数据结构,以了解资源的情况。只要发现所需资源R正处于忙碌状态,线程便转为等待状态, 并对mutex执行开锁操作后,等待该资源被释放;若资源处于空闲状态,表明线程可以使用该资源,于是将该资源设置为忙碌状态,再对mutex执行开锁操作。

下面给出了对上述资源的申请(左半部分)和释放(右半部分)操作的描述。

   Lock mutex                      Lock mutex

   check data structures;          mark resource as free;

   while(resource busy);           unlock mutex;

    wait(condition variable);       wakeup(condition variable);

   mark resource as busy;

    unlock mutex;

 

信号量机制

(1) 私用信号量(private samephore)。

    当某线程需利用信号量来实现同一进程中各线程之间的同步时,可调用创建信号量的命令来创建一私用信号量,其数据结构是存放在应用程序的地址空间中。私用信号量属于特定的进程所有,OS并不知道私用信号量的存在,因此,一旦发生私用信号量的占用者异常结束或正常结束,但并未释放该信号量所占有空间的情况时,系统将无法使它恢复为0(空), 也不能将它传送给下一个请求它的线程。

(2) 公用信号量(public semaphort)。

    公用信号量是为实现不同进程间或不同进程中各线程之间的同步而设置的。由于它有着一个公开的名字供所有的进程使用,故而把它称为公用信号量。其数据结构是存放在受保护的系统存储区中,由OS为它分配空间并进行管理,故也称为系统信号量。如果信号量的占有者在结束时未释放该公用信号量,则OS会自动将该信号量空间回收,并通知下一进程。可见,公用信号量是一种比较安全的同步机制。

 

内核支持线程和用户级线程

1. 内核支持线程

是在内核的支持下运行的,即无论是用户进程中的线程,还是系统进程中的线程,他们的创建、撤消和切换等,也是依靠内核实现的。此外,在内核空间还为每一个内核支持线程设置了一个线程控制块,内核是根据该控制块而感知某线程的存在的,并对其加以控制。

2. 用户级线程

用户级线程仅存在于用户空间中。对于这种线程的创建、 撤消、线程之间的同步与通信等功能,都无须利用系统调用来实现。对于用户级线程的切换,通常是发生在一个应用进程的诸多线程之间,这时,也同样无须内核的支持。由于切换的规则远比进程调度和切换的规则简单,因而使线程的切换速度特别快。可见,这种线程是与内核无关的。

你可能感兴趣的:(学生时代专业课程学习整理)