zoukankan      html  css  js  c++  java
  • 进程同步

    一、进程同步(包括进程同步和进程互斥两个方面)

           进程是操作系统的核心,进程引进的目的就是为了程序能并发执行,提高资源利用率和系统的吞吐量。这里并发不等于并行。 并发 指:在 一 定时间内 物理机器上有两个或两个以上的程序同处于 开始运行但尚未结束 的状态,并且次序不是事先确定的。在单处理机系统中同时存在多个并发程序,从宏观上看这些程序是同时在执行的。从微观上讲任何时刻只有一个程序在执行,这些程序在 CPU 上轮流执行。 
    并行 : 指 严格的同时 执行,在多处理机系统中才可能。

    (并发和并行的线性图)

        并 发进程间的关系可以是无关的,也可以是有交往的。并发进程间无关是指它们是各自独立的,即如果一个进程的执行不影响其他进程的执行,且与其他进程的进展情 况无关,不需要特别的控制,不在这节课的讨论范围;并发进程间有交往是指一个进程的执行可能影响其他进程的执行结果,即一个进程的执行依赖其他进程的进展 情况。有交往的并发进程一定共享某些资源。

       进程之间互相竞争某一个资源,这种关系就称为进程的 互斥 ,也就是说对于某个系统资源,如果一个进程正在使用,其他的进程就必须等待其用完,不能同时使用。例如, A,B 两个进程共享一台打印机,如果系统已经将打印机分配给了 A进程,当 B 进程需要打印时因得不到打印机而阻塞,只有 A 进程将打印机释放后,系统才将 B 进程唤醒, B 进程才有可能获得打印机。

          并发进程使用共享资源时,除了竞争之外有协作,要利用互通消息的办法来控制执行速度,使相互协作的进程正确工作。

       进程之间的相互合作来完成某一任务,把这种关系称为进程的 同步 。例如(生产者和消费者) A,B 两个进程通过一个缓冲区合作完成一项任务, A 进程将数据送入缓冲区后通知 B 进程缓冲区中有数据, B 进程从缓冲区中取走数据再通知 A 进程缓冲区现为空。当缓冲区空时, B 进程因得不到数据而阻塞,只有当 A 进程将数据送入缓冲区的时才将 B 进程唤醒。反之,当缓冲区满时, A 进程不能继续送数据而阻塞,只有当 B 进程取走数据时才唤醒 A 进程。

              有交往的并发进程可能会同时使用共享资源,如果对这种情况不加控制,在使用共享资源时会出错。(在后面的例题中我们会看到如果不加控制结果可能会出错)。两个进程管理交通路口的自动计数系统。观察者识别卡车并计数,报告者定时把观察者的计数值打印输出,然后把计数值清 0 。当这两个进程并发执行时;若报告者进程执行时无卡车通过,则能正确统计某时间段内的卡车数量;若报告者进程执行时有卡车通过,统计结果会产生错误。 造成不正确的因素与进程占用处理器的时间、执行的速度及外界的影响有关。而这些因素都与时间有关,所以称为与时间有关的错误。

    在此提一两个概念,在后面会用到。 临界资源、临界区 。临界资源是指系统中一次只允许一个进程使用的资源(可以是硬件资源像打印机, 也包括软件资源,如程序中的数据结构、表格和变量、文件等。) 访问临界资源的那段代码称为临界区。

     

    过渡:

        对进程的互斥和同步,操作系统必须采取某种控制手段,以保证进程的安全可靠执行。对互斥,要保证在临界区内不能交替执行,而谁先进入临界区都是可以的。对 同步,则要保证合作进程必须相互配合共同推进,并严格按照一定的先后顺序。用什么来保证进程的同步和互斥呢,这就是接下来讲的第二个方面的内容:信号量机 制。也是我们这节课的重点。

    二、信号量与PV 操作

    对 实现进程的同步和互斥而言,信号量是一种很有效的工具,现已被广泛的应用于单处理机系统、多处理机系统和计算机网络中。信号量取自交通管理中的信号灯的概 念,信号灯是用于控交通的,通过对信号灯的控制来控制交通流向,借其含义用信号量来作为一种控制进程互斥和同步的变量,也就是通过控制信号量来控制进程的 同步与互斥。

    PV 原语的含义

          每个信号量至少须记录两个信息:信号量的值和等待该信号量的进程队列。它的类型定义如下:(用类 PASCAL 语言表述) 
        semaphore = record 
             value: integer; 
             queue: list of process; 
           end; 
      
    s.value>=0 时, s.queue 为空; 
    s.value<0 时, s.value 的绝对值为 s.queue 中等待进程的个数;

    信号量 semaphofre( 这里简称 S) 是一整数, S 大于等于零时代表可供并发进程使用的资源实体数,但 S 小于零时它的绝对值则表示正在等待使用临界区的进程数。除了对信号量 S 进行初始化外,只能对 S 进行两个原子操作: P(s) 和 V(s) ,简称 P 、 V 操作。 P 操作和 V 操作是不可中断的程序段,称为原语。 ( 和数据库操作中的事务是一样的,具有原子性,要么全做,要么不做 )

      原语操作的动作 是:(对资源的申请,如果有资源,则进程继续执行;否则进程被阻塞,然后转进程调度)

    Prodedure p(s)

      Var s : semaphore

      Begin

         s.value:=s.value-1;

          if s.value<0 then block (s.l)  

      End

      原语操作的动作 是:(对临界资源的释放,如果有等待该资源的阻塞进程,那么就唤醒一个等待的进程,然后再返回原进程继续执行或转进程调度。)

    procedure V(s)

       Var s : semaphore

      Begin

          s.value:=s.value+1;

          if s.value<=0 then wakeup (s.l)  

      end

    每次的 操作, 意味着请求分配一个单位的资源,因此描述为 s.value:=s.value-1 ;当 s.value<0 时,表示资源已分配完毕,因此进程阻塞,此时 s.value 的绝对值表示该信号量链表中阻塞进程的数目。 每次 操作 ,表示释放一个单位资源,故进行 s.value=s.value+1 操作;若加 1 后仍有 s.value<=0 ,则表示该信号量链表中仍有阻塞进程,故而应将s.l 链表中的第一个等待进程唤醒, |s.value| 表示阻塞的进程数。

    在 PV 原语执行期间不允许有中断的发生。

    三、PV 操作实现进程同步与互斥

    1. 用PV 原语实现进程的互斥

           对于互斥的信号量 S 与所有的并发进程有关,所以称之为公有信号量。只要把临界区置于 P(S) 和 V(S) 之间,即可实现进程间的互斥。(这样,每个想访问临界资源的进程,在进入临界区之前,要先对信号量 S 执行 P操作,若该资源未被访问,则本次 P 操作成功,该进程便可以进入自己的临界区,这时若再有其他的进程想进入自己的临界区,在对信号量 S 执行 P 操作后必然会失败而阻塞,从而保证了临界资源被互斥的访问。当访问临界资源的进程退出临界区后,应该再对 mutex 执行 V 操作,释放该临界资源。)就象火车中的每节车厢只有一个卫生间,该车厢的所有旅客共享这个公有资源:卫生间,所以旅客间必须互斥进入卫生间,只要把卫生间放在 P(S)和 V(S) 之间,就可以到达互斥的效果。以例子说明进程的互斥实现。

        例 1 :观察者和报告者是两个并发执行的进程,观察者不断观察并对通过的卡车计数,报告者定时的将观察者的计数值打印,两个进程并发执行的程序如下: 
    count:integer;
    count:=0;
    process observer
    begin
    L1: observe a car;/* 观察到一辆卡车 */
    count:=count+1;
    goto L1
    end;
    process reporter
    begin
    L2:print count;
    count:=0;
    goto L2
    end;

    请用PV 操作进行管理使其不产生与时间有关的错误。

    分析:观察者和报告者共享了变量 count ,观察者进程的临界区是 “count : =count+1” ,报告者进程的临界区是 “print count; count : =0” 。按给出的程序,对临界区的执行没有限制,当它们并发执行时对共享变量 count 会出现如下三种操作序列: 
    count : =count+1; print count ; count : =0 ; 
    print count ; count : =0 ; count : =count+1 ;                                     print count;count : =count+1 ; count : =0 ; 
    按第一、二种序列执行时,总能把观察者在一段时间里观察到的卡车数正确打印出来,然后再重新开始计数。而按第三种序列执行时,在打印了某段时间里观察到的卡车数后,观察者又观察到有一辆卡车通过作 count+1 ,但由于接下去执行的是 count : =0 ,以后观察者将从 “0” 开始计数,于是打印出来的 count 值的总和将比实际观察到的卡车数少。这种与时间有关的错误是因为它们同时在临界区执行,两个进程交替地访问了共享变量 count 而造成地。要操作结果正确,那么观察者进程和报告者进程之间应该互斥地访问临界区,也就是观察者进程在访问它的临界区时,报告者进程不能访问自己的临界区。 对互斥,要保证在临界区内不能交替执行,而谁先进入临界区都是可以的。 用 PV 操作管理时。只要保证互斥进入临界区即可。(在前面的代码中加 PV 操作) 
    解答: 
    begin
    count:integer;
    S : semaphore;
    count:=0;s:=1;


    cobegin
    process observer
    begin
    L1: observe a car;/* 观察到一辆卡车 */
    P(s);
    count:=count+1;
    V(s);
    goto L1
    end;


    process reporter
    begin
    L2:

    P(s); 
    print count;
    count:=0;
    V(s); 
    goto L2
    end;
    coend;
    end;

    互斥   注意:   判断进程间是否互斥,关键是看进程间是否共享某一公有资源,一个公有资源与一个信号量相对应。在实现互斥时应注意:

    1).P ( mutex )和 v(mutex) 必须成对出现,缺少一个都不行。 缺少 P ( mutex )将会引起系统混乱,不能保证对临界资源的互斥访问;缺少 v(mutex) 将会使该临界资源永久不被释放,从而因等待该资源而阻塞的进程不再被唤醒。

    2). P(S) 和V(S) 的调用一定紧挨着临界区的前、后。比如,在观察者进程中若把P(S) 放到“ observe a car ” 之前,则会降低系统并发能力;若把V(S) 放到“goto L1” 之后,则会造成系统瘫痪。

         2.  用PV 原语实现进程的同步

    与进程互斥不同,进程同步时的信号量只与制约进程及被制约进程有关而不是与整组并发进程有关,所以称该信号量为私有信号量。利用 PV 原语实现进程同步的方法是:首先判断进程间的关系为同步的,且为各并发进程设置私有信号量,然后为私有信号量赋初值,最后利用 PV 原语和私有信号量规定各进程的执行顺序。   

        

           这里,消费者和生产者进程之间的同步为例来说明。因为计算机系统中的许多问题都可以被归结为生产者和消费者关系。我们可以通过一个缓冲区把生产者和消费者联系起来。生产者把产品生产出来,送入仓库。给消费者发信号,消费者得到信号后,到仓库取产品,取走产品后给生产者发信号 …… 这里假设仓库中只能放一个产品。当仓库满时,生产者不能放产品;当仓库空的时候,消费者不能取产品。

    产品

    仓 库

    一个生产者

    一个消费者

    生产者只关心仓库是否为空,消费者只关心仓库中是否满。可设置两个信号量 empty , full ,其实初值为 1,0 。 full 表示仓库中是否满, empty 表示仓库是否为空。 同步算法描述如下:

    Var full,empty: semaphore:=0,1;

    Begin

           Parbegin

                  Pp: begin// 生产者进程

                         Repeat

                    P(empty);

                                Produce one and add to buffer

                                V(full);

                         Until false

                         End

                  Pc:begin// 消费者进程

                         Repeat

                                P(full);

                                Take from the buffer;

                                V(empty);

                         Until false

                         End

           Parend

    End

           生产进程和消费者进程是并发执行的进程,假定生产进程先执行,它执行 P(empty) 成功,它把生产产品放入缓冲区,并执行 V(full) 操作,使 full = 1 ,表示在缓冲区中已有可供消费的产品,然后执行 P(EMPTY) 操作将自己阻塞起来,等待消费进程将缓冲区中数据取走。当调度程序调度到消费进程执行时,由于 FULL=1 ,故 P ( FULL )成功,可以从缓冲区中取走产品消费,并执行 V ( EMPTY )操作,将生产进程唤醒,然后又返回到进程的开始去执行 P(FULL) 操作将自己阻塞起来,等待生产进程送来下一个产品,接下去又是生产进程执行。这样,便保证了生产进程和消费进程依次轮流执行,从而实现了两进程间的同步。

           如果现在假定一开始是消费进程先执行,由于 FULL 的初值为 0 ,故在执行 P(FULL) 后便阻塞起来了,当调度到生产进程执行时,它把产品放入缓冲区,并执行 V(FULL) 操作,把消费进程唤醒,再执行 P(EMPTY) 操作将自己阻塞,接下去又是消费进程执行。综上所述可以看出:此同步算法保证了两个进程按照生产――消费――生产的次序执行。更具体地说:( 1 )当生产进程未把产品放入缓冲时,消费进程不能执行。( 2 )消费进程未把产品从缓冲区取走,生产进程不能执行。

         用 PV 操作还可以实现进程同步与互斥的混合问题,典型的如:多个生产者和多个消费者共享容量为 n 的缓存区。这些问题都可以根据我们刚才讲的同步和互斥来完成,但是有很多细节需要注意的,做为下节课的内容讲解。

    四、总结用PV 操作解决进程同步、进程互斥的要点

    同步和互斥这两种制约关系的区别:进程的互斥是进程间竞争兵享资源的使用权,这种竞争没有固定的必然关系;而进程同步时,涉及到共享资源的并发进程之间有一种必然的依赖关系。

    用PV操作解决进程同步问题时首先应确定问题是属于进程互斥还是进程同步,或是互斥与同步的混合问题。然后根据共享资源的数量以及使用共享资源的规则正确的定义信号量及其初值。然后决定在不同信号量上应实施的 P 操作和 V操作,用这些 P 操作和 V 操作保证并发进程正确地使用共享资源。

    用 PV 操作实现进程的互斥 ,只要用一个信号量与一组相关临界区联系起来,信号量的初值定义为“ 1”。每个进程要进入临界区之前调用 P 操作,测试自己是否可以立即进入临界区;执行完临界区的程序段后,调用 V 操作表示自己退出临界区。

    用 PV 操作实现进程的同步 时应定义一组信号量,其中每个信号量与一个消息对应,根据各个消息量的物理含意确定初值。进程通过调用 P 操作来测定自己需要的消息是否到达,通过调用 V 操作把其它进程需要的消息发送出去。

    SRC: http://blog.csdn.net/sunrisefe/archive/2005/12/06/544799.aspx

  • 相关阅读:
    Python 发送邮件
    python3 根据时间获取本月一号和月末日期
    docker搭建MediaWiki
    linux下僵尸进程的发现与处理
    rootkit后门检查工具RKHunter
    CentOS7安装Node_exporter(二进制)
    用JS获取地址栏参数的方法(超级简单)
    php读取目录及子目录下所有文件名的方法
    css input[type=file] 样式美化,input上传按钮美化
    APACHE REWRITE ? 匹配问号的写法
  • 原文地址:https://www.cnblogs.com/flypiggy/p/3181441.html
Copyright © 2011-2022 走看看