进程管理3--经典的进程同步问题

管程机制

用信号量机制实现进程间的同步和互斥,既方便又有效。但存在以下两个问题:

  • 每个访问临界资源的进程都必须自备同步操作(P、V操作),这使大量的同步操作分散在各个进程中,给系统的管理带来麻烦。
  • 会因同步操作使用不当而导致系统死锁。

解决方法:

管程(Monitors)

Dijkstra于1971年提出:为每个共享资源设立一个“秘书”来管理对它的访问。 
一切来访者都要通过秘书,而秘书每次仅允许一个来访者(进程)来访问共享资源。这样既便于系统管理共享资源,又能保证进程的互斥访问和同步。1973
年,Hanson和Hoare又把“秘书”概念发展为管程概念。      

基本思想

     系统中的各种软硬件资源,其特性都可用数据结构抽象地描述,把对该共享数据结构实施的操作定义为一组过程。

     进程对共享资源的访问都是通过这组过程对共享数据结构的操作来实现的,这组过程可以根据资源的使用情况,接受或阻塞进程的访问,确保每次只有一个进程使用共享资源,

实现进程的互斥。

管程的定义

    一个数据结构和在该数据结构上能被并发进程所执行的一组操作,这组操作能同步进程和改变管程中的数据。如下图所示:

管程的结构

TYPE <管程名> = MONITOR

  <共享变量说明>;

  procedure<过程名>(<形式参数表>);

    begin

      <过程体>;

    end;

  ……

  procedure <过程名>(<形式参数表>);

    begin

      <过程体>;

    end;

  begin

    <管程的局部数据初始化语句序列>;

  end;

管程相当于围墙,它把共享变量和对它进行操作的若干过程围了起来,所有进程要访问临界资源时,都必须经过管程才能进入,而管程每次只允许一个进程进入管程,从而实现进程互斥。

管程的特性

模块化:是一个基本程序单位,可单独编译

抽象数据类型:管程中不仅有数据,而且有对数据的操作

信息隐蔽:数据结构和过程的具体实现外部不可见

管程与进程作比较

管程定义的是公用数据结构,而进程定义的是私有数据结构PCB;

管程把共享变量上的同步操作集中起来,而临界区却分散在每个进程中;

管程是为管理共享资源而建立的,进程主要是为占有系统资源和实现系统并发性而引入的;

管程是被要使用共享资源的进程所调用的,管程和调用它的进程不能并发工作,而进程之间能并发工作,并发性是进程的固有特性;

管程是OS中一个资源管理模块,供进程调用;而进程有生命周期,由创建而产生、由撤销而消亡

经典进程的同步问题

在多道程序环境下,进程同步问题十分重要,出现一系列经典的进程同步问题,其中有代表性有:

  • 生产者—消费者问题
  • 哲学家进餐问题
  • 读者—写者问题

一、“生产者—消费者”问题

问题描述:

      “生产者---消费者”问题是最著名的进程同步问题。它描述了一组生产者向一组消费者提供产品,它们共享一个缓冲池(有n个缓冲区),生产者向其中投放产品,消费者从中取得产品。

      它是许多相互合作进程的抽象,如输入进程与计算进程;计算进程与打印进程等。

一个生产者,一个消费者,公用一个缓冲区

定义两个同步信号量:

  empty——表示缓冲区是否为空,初值为1。

  full——表示缓冲区中是否为满,初值为0。

//生产者进程:
while(TRUE){
  生产一个产品;
  P(empty);
  把产品送往Buffer;
  V(full);
}
//消费者进程:
while(TRUE){
  P(full);
  从Buffer取出一个产品;
  V(empty);
  消费产品;
}

扩展:M个生产者,K个消费者,公用有n个缓冲区的缓冲池

     
设缓冲池的长度为n(n>0),一群生产者进程P1,P2,…,Pm,一群消费者进程C1,C2,…,Ck,如图所示。假定生产者和消费者是相互等
效,只要缓冲池未满,生产者就可以把产品送入缓冲区,类似地,只要缓冲池未空,消费者便可以从缓冲区取走产品并消耗它。生产者和消费者的同步关系将禁止生
产者向满的缓冲池输送产品,也禁止消费者从空的缓冲池提取产品。

设置两个同步信号量及一个互斥信号量

empty:说明空缓冲区的数目,其初值为缓冲池的大小n,表示消费者已把缓冲池中全部产品取走,有n个空缓冲区可用。

full:说明满缓冲区的数目(即产品数目),其初值为0,表示生产者尚未把产品放入缓冲池,有0个满缓冲区可用。

mutex:  说明该缓冲池是一临界资源,必须互斥使用,其初值为1。

 “生产者—消费者”问题的同步算法描述:

semaphore  full=0;  /*表示满缓冲区的数目*/
semaphore  empty=n;  /*表示空缓冲区的数目*/
semaphore  mutex=1;  /*表示对缓冲池进行操作的互斥信号量*/
main()
{
  cobegin
     producer();
     consumer();
  coend
 }
producer()
{
  while(true) {
        生产一个产品放入nextp;
        P(empty);
        P(mutex);
        Buffer[in]=nextp;
        in=(in+1) mod n;
        V(mutex);
        V(full);
  }
}
consumer()
{
  while(true) {
     P(full);
     P(mutex);
     nextc =Buffer[out];
     out=(out+1) mod n;
     V(mutex);
     V(empty);
     消费nextc中的产品;
  }
}

“生产者-消费者”问题中应注意:

1. 互斥信号量的P、V操作在每一进程中必须成对出现。

2. 对资源信号量(full,empty)的P、V操作也必须成对出现,但可分别处于不同的程序中。

3. 多个P操作顺序不能颠倒。

4. 先执行资源信号量的P操作,再执行互斥信号量的P操作,否则可能引起进程死锁。

5. 它是一个同步问题:

   (1)消费者想要取产品,缓冲池中至少有一个缓冲区是满的。

   (2)生产者想要放产品,缓冲池中至少有一个缓冲区是空的。

6. 它是一互斥问题

    缓冲池是临界资源,因此,各生产者进程和各消费者进程必须互斥访问。

用管程机制解决生产者—消费者问题

1、建立Producer-consumer(PC)管程

   Type PC=monitor
    var in,out,count:integer;
          buffer:array[0,…,n-1] of item;
          notfull,notempty:condition;
          put(item);
          get(item);
     begin
          in:=out:=0;       /* 初始化代码*/
          count:=0;
     end

管程中的两个条件变量:

(1) notfull  表示等待未满缓冲区(空缓冲区)。

(2)notempty 表示等待未空缓冲区(满缓冲区)。

1、建立Producer-consumer(PC)管程

put(item)过程

          生产者利用此过程将自己生产的产品放到缓冲池中,若发现缓冲池已满(count    n),则等待。

get(item)过程

         消费者利用此过程将缓冲池中的产品取走,若发现缓冲池已空(count   0),则等待。

put(item)
Procedure entry put(item)
       begin
            if  count >=  n  then
                 notfull.wait;
            buffer(in):=nextp;
            in:=(in+1) mod n;
            count:=count+1;
            if notempty.queue then
                  notempty.signal;
       end
get(item)
Procedure entry get(item)
       begin
            if  count =  0  then
                 notempty.wait;
            nextc:=buffer(out);
            out:=(out+1) mod n;
            count:=count-1;
            if notfull.queue then
                notfull.signal;
       end

2、生产者—消费者问题的解决

Producer:begin
                   repeat
                      produce an item in nextp;
                      PC.put(item);
                   until false
                  end
Consumer:begin
                    repeat
               PC.get(item);
                        consume the item in nextc;
                     until false
                   end

二、“哲学家进餐”问题

问题描述:

      有五个哲学家,他们的生活方式是交替地进行思考和进餐。他们共用一张圆桌,分别坐在五张椅子上。在圆桌上有五个碗和五支筷子,平时一个哲学家进行思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐毕,放下筷子又继续思考。

哲学家进餐问题可看作是并发进程并发执行时,处理共享资源的一个有代表性的问题。

哲学家进餐问题的解决:

semaphore  stick[5]={1,1,1,1,1};  /*分别表示5支筷子*/
main()
{
  cobegin
     philosopher(0);
     philosopher(1);
     philosopher(2);
     philosopher(3);
     philosopher(4);
  coend
 }
//第i个哲学家的活动算法
philosopher(int i)
{
  while(true) {
    思考;
    P(stick[i]);
    P(stick[(i+1) mod 5]);
    进餐;
    V(stick[i]);
    V(stick[(i+1) mod 5]);
  }
}

说明:

1、此算法可以保证不会有相邻的两位哲学家同时进餐。

2、若五位哲学家同时饥饿而各自拿起了左边的筷子,这使五个信号量stick均为0,当他们试图去拿起右边的筷子时,都将因无筷子而无限期地等待下去,即可能会引起死锁。

上述解法可能出现永远等待,有若干种办法可避免死锁:

  • 至多允许四个哲学家同时进餐(解决方法一);
  • 奇数号先取左手边的筷子,偶数号先取右手边的筷子(解决方法二);
  • 每个哲学家取到手边的两把筷子才进餐,否则一把筷子也不取(解决方法三)。

解决的方法(一)

设置一个信号量Sm,其初值为4,用于限制同时进餐的哲学家数目至多为4,这样,第i个哲学家的活动可描述为:

   while(true)
   {                                             signal(stick[i]);
      wait(Sm);                                  signal(stick[(i+1) mod 5]);
      wait(stick[i]);                            signal(Sm);
      wait (stick[(i+1) mod 5]);                 …...
      ……                                         think;
      eat;                                       }
      …...

解决的方法(二)

    while(true)                                   signal(stick[i]);
    {if odd(i)                                      signal (stick[(i+1) mod 5]);
      {wait(stick[i]);                           …...
        wait (stick[(i+1) mod 5]);         think;
      }                                                …...
      else                                           }
      {wait (stick[(i+1) mod 5]);
        wait(stick[i]);
      }
      ……
      eat;
      …...

对5个哲学家,假设规定:单号者进餐时,先拿左手(i)的筷子,然后再拿右手(i+1)的筷子。双号则先右后左。这样既可使5个人同时进餐,又不致产生死锁。

解决的方法(三)

利用AND信号量机制解决哲学家进餐问题

semaphore  stick[5]={1,1,1,1,1};
philosopher(int i)
{
     while(true)
     {
        think;
        Swait(stick[(i+1) mod 5],stick[i]);
        eat;
        Ssignal(stick[(i+1) mod 5],stick[i]);
        }
}

三、“读者—写者”问题

问题描述:

     一个数据对象(数据文件或记录)可被多个进程共享。其中,读者(reader)进程要求读,写者(writer)进程要求写或修改。

     为了保证读写的正确性和数据对象的一致性,系统要求:当有读者进程读文件时,不允许任何写者进程写,但允许多个读者同时读;当有写者进程写时,不允许任何其它写者进程写,也不允许任何读者进程读。

“读者—写者”问题的同步算法描述

设置一个共享变量和两个信号量:

共享变量readcount:记录当前正在读数据集的读进程数目,初值为0。

读互斥信号量rmutex :表示读进程互斥地访问共享变量readcount,初值为1.

写互斥信号量wmutex:表示写进程与其它进程(读、写)互斥地访问数据集,初值为1.

“读者—写者”问题的同步算法描述

semaphore  rmutex=1;
semaphore  wmutex=1;
int  readcount=0;
main()
{
  cobegin
     reader();
     writer();
  coend
}
reader()
{
    while(true) {
        P(rmutex);
        if(readcount= =0) P(wmutex);/*第一位读者阻止写者*/
        readcount++;  //修改readcount
        V(rmutex);
        读数据集;
        P(rmutex);
        readcount--;  //修改readcount
        if(readcount= =0) V(wmutex);/*第末位读者允许写者进*/
        V(rmutex);
    }
}
writer()
{
  while(true) {
       P(wmutex); // 阻止其它进程(读、写);
       写数据集;
       V(wmutex); // 允许其它进程(读、写);
  }
}
时间: 2024-10-29 18:42:57

进程管理3--经典的进程同步问题的相关文章

简述linux的进程管理和作业任务

进程是为了使多个程序可以并发的执行,提高系统的资源利用和吞吐量 1.linux中每个进程都有一个识别号PID 2.系统第一个启动进程是init,PID是1,是唯一一个由系统内核直接运行的进程,新的进程都是系统调用fork来产生,除了init之外,每个进程都有一个父进程. 3每个进程有实际用户识别号(运行此进程的用户识别号),实际组识别号(运行此进程的组识别号). 4.进程的类型,交互进程,由一个Shell启动的进程. 批处理进程,不与特定的终端相关联,提交到等待队列中顺序执行的进程. 守护进程,

Linux进程管理及作业控制

Linux是一个多任务的操作系统,系统上同时运行着多个进程,正在执行的一个或多个相关进程称为一个作业.使用作业控制,用户可以同时运行多个作业,并在需要时在作业之间进行切换.本章详细介绍进程管理及作业控制的命令,包括启动进程.查看进程.调度作业的命令. 进程及作业的概念 Linux是一个多用户多任务的操作系统.多用户是指多个用户可以在同一时间使用计算机系统:多任务是指Linux可以同时执行几个任务,它可以在还未执行完一个任务时又执行另一项任务. 操作系统管理多个用户的请求和多个任务.大多数系统都只

linux进程管理之进程创建

所谓进程就是程序执行时的一个实例. 它是现代操作系统中一个很重要的抽象,我们从进程的生命周期:创建,执行,消亡来分析一下Linux上的进程管理实现. 一:前言 进程管理结构; 在内核中,每一个进程对应一个task.就是以前所讲的PCB.它的结构如下(include/linux/sched.h): struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack; at

Linux进程管理的4个常用命令

Linux是一个多用户.多任务的操作系统.在这样的系统中,各种计算机资源(如文件.内存.CPU等)的分配和管理都以进程为单位.为了协调多个进程对这些共享资源的访问,操作系统要跟踪所有进程的活动,以及它们对系统资源的使用情况,从而实施对进程和资源的动态管理.进程在一定条件下可以对诸如文件.数据库等客体进行操作.如果进程用作其他不法用途,将给系统带来重大危害.在现实生活当中,许多网络黑客都是通过种植"木马"的办法来达到破坏计算机系统和入侵的目的,而这些"木马"程序无一例

金山毒霸如何使用进程管理器

  金山毒霸的进程管理器,是利用了"互联网可信认证"技术的进程管理器,能够实时标注出系统中存在的木马.病毒.恶意软件等可疑与威胁进程,同时加入了详尽的进程描述信息,帮助快速定位威胁源.管理进程. 在"安全百宝箱"主界面点击"进程管理器"按钮,在左侧的面板中显示了计算机系统中正在运行的所有进程,右侧面板对应了这些进程的相关信息,包括名称,路径等. 单击"找出风险进程",会进行快速风险进程定位,对于确实有风险的进程,可以选中它并点

linux进程管理和作业任务

  进程是为了使多个程序可以并发的执行,提高系统的资源利用和吞吐量 1.linux中每个进程都有一个识别号PID 2.系统第一个启动进程是init,PID是1,是唯一一个由系统内核直接运行的进程,新的进程都是系统调用fork来产生,除了init之外,每个进程都有一个父进程. 3每个进程有实际用户识别号(运行此进程的用户识别号),实际组识别号(运行此进程的组识别号). 4.进程的类型,交互进程,由一个Shell启动的进程. 批处理进程,不与特定的终端相关联,提交到等待队列中顺序执行的进程. 守护进

WinXP下如何删除进程管理器中的GoogleUpdate进程

  使用WinXP系统的朋友经常都会用到进程管理器,进程管理器可以帮你监控到每一个悄悄在后台运行的程序.有不少细心的WinXP用户会发现,进程管理器中总是出现GoogleUpdate.exe进程,看名字我们就知道用户一定是安装了Google相关程序,虽然可以将该进程强行终止,不过每次开机后又会出现,而且无论你怎么查找启动项,禁止Google Update Service它都一直会出现,这确实是一个棘手的问题,难道真没有解决方法了吗?为了解决这个问题我们还应当了解它的运行方式. 既然GoogleU

Win7系统巧用Windows进程管理器

  Windows进程管理器是一款功能比较强大的进程管理工具,可以进程查询.进程管理,包括结束进程.暂停进程.恢复进程.删除进程等,还可以进行端口访问查询.查看系统性能信息等. 1.进程管理 在win7系统中运行该软件,主界面将所有功能分为了进程管理.端口监听.系统信息三大部分:软件对进程的管理和允许用户对进程的操作等非常全面.对于每一个进程,用户除了可以查看其详细进程信息外,用户还可以随时结束指定进程和删除指定进程. 在对进程操作方面,该软件非常有特色:首先是"暂停进程"功能,这一功

优化大师进程管理大师

在Windows3x的时代,尽管Windows像一个多线程的进程来完成操作,在多个应用程序之间共享CPU时间,让每个应用程序都有机会执行,但所有应用程序必须是单线程的.Windows9x/NT/2000/XP/2003后,Windows像Unix一样全面支持多线程,Windows本身提供对线程的同步和调度功能.既然如此为什么Windows优化大师还要提供进程管理的软件呢?因为Windows9x和WindowsNT/2000/XP/2003的本质区别是Windows9x为试验式抢先多任务操作系统,