zoukankan      html  css  js  c++  java
  • 用管程解决生产者消费者问题

    生产者消费者问题

    系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。 生产者,消费者共享一个初始化为空,大小为n 的缓冲区。 如何使用信号量机制(P、V操作)实现生产者、消费者进程的这些功能呢? 信号量机制可实现互斥、同步、对一类系统资源的申请和释放。

    对于信号量可以看这篇信号量机制

    使用信号量解决生产者消费者问题

    生产者、消费者共享一个初始为空、大小为n的缓冲区。只有缓冲区没满的时候,生产者才能把产品放入缓冲区,否则必须等待。只有缓冲区不为空的时候,消费者才能从中取出产品,否则必须等待。

    缓冲区是临界资源,各个进程必须互斥访问。
    首先定义信号量;

    semaphore mutex=1; //互斥信号量,实现对缓冲区的互斥访问
    semaphore empty=n; //同步信号量,表示空闲缓冲区的数量
    semaphore full = 0; //同步信号量,表示产品数量,也是非空缓冲区的数量
    
    producer(){
        while(1){
            生产一个产品;
            p(empty);  //小号一个空闲缓冲区
            p(mutex);  // 实现互斥是在同一进程中进行PV操作
            把产品放入缓冲区;
            V(mutex);
            V(full); //增加一个产品
        }
    
    }
    // 实现两个进程的同步,是在其中一个进程中执行P,另一个进程中执行V。
    
    consumer(){
        while(1){
            P(full); //消耗一个产品
            P(mutex);
            从缓冲区取出一个产品
            V(mutex);
            V(empty);   //增加一个空闲缓冲区
            使用产品;
        
        }
    
    }
    
    

    管程

    为啥要引入管程?

    信号量机制存在问题:编写程序困难、易出错。能不能设计一种机制,让程序员写程序时不需要再关注复杂的PV操作,让写代码更加轻松呢?

    1973年, Brinch Hansen首次在程序设计语言( Pascal中引入了“管程”成分一一一种高级同步机制)

    管程的定义和基本特征

    定义

    管程是一种特殊的软件模块,由这些部分组成:

    1. 局部于管程的共享数据结构说明;
    2. 对该数据结构进行操作的一组过程(函数)
    3. 对局部于管程的共享数据设置初始值的语句
    4. 管程自己的名字

    特征

    1. 管程内的数据只能被管程中定义的函数(过程)访问;(类比于java实体类的get方法)
    2. 一个进程只能通过调用管程内的过称(函数/方法)才能进入管程访问共享数据(进程.getXxx())
    3. 每次仅仅允许一个进程在管程内自行某个内部的过程

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

    定义一个管程以下是伪代码

    monitor ProducterConsumer
        condition full,empty;  //条件变量用来实现同步(排队)
        int count=0; // 缓冲区中的产品数
        void insert(Item item){
        //把产品item放入缓冲区
        if(count == N)
            wait(full);
        count++;
        insert_item(item);
        if(count == 1)
            signal(empty);
        
        }
    Item remove(){ //从缓冲区取出一个产品
        if(count==0)
            wait(empty);
        count--;
        if(count == N-1)
            signal(full);
        return remove_item();
    }
    end monitor;
    

    生产者进程

    producter(){
        while(1){
            item = 生产一个产品;
            ProducterConsumer.insert(item);
           }
    }
    

    消费者进程

    consumer(){
        while(1){
            item = ProducterConsumer.remove();
            消费产品;
        
        }
    }
    

    引入管程的目的无非就是更方便地实现进程的互斥与同步

    1. 需要在管程中定义共享数据
    2. 需要在管程中定义用于访问这些共享数据的“入口”–其实就是一些函数
    3. 只有通过这些函数才能访问管程中的共享数据
    4. 管程中有很多接口,但是每次只能开放其中一个入口,并且只能让一个进程或线程进入,(互斥的特性交给了编译器去实现,程序员不用关心)
    5. 可在管程中设置条件变量级等待/唤醒操作以解决同步问题。

    通过管程提供特定的接口来实现进程的同步与互斥,这就是一种封装的思想。

  • 相关阅读:
    js 与 asp.net 验证控件冲突解决方法
    图片处理(给图片加水印)
    JS打开窗口
    ASP.NET编程中的十大技巧
    【ASP.NET】FCKeditor 2.6 + Asp.Net 设置
    XML文件设置树形结构(无限级)原创
    利用vs.net快速开发windows服务(c#) (转载)
    C#反射 学习
    C#解压RAR压缩文件(转载测试通过)
    SQL显示字段信息
  • 原文地址:https://www.cnblogs.com/dataoblogs/p/14121889.html
Copyright © 2011-2022 走看看