C, PHP, VB, .NET

Дневникът на Филип Петров


* Consumer-Producer – двустранна синхронизация с много консуматори и много производители

Публикувано на 29 ноември 2013 в раздел ПИК3 Java.

В предишните примери се забеляза нещо много неприятно – кодът се обърква все повече и повече. Причината за това е, че при множество играчи, не само производителя трябва да уведомява консуматора и обратно, а и самите консуматори и самите производители трябва да се синхронизират помежду си. Поради тази причина ще е по-добре ако оптимизираме идеята за централно синхронизиране на всички чрез „чинията“.

В този пример има споделен ресурс – чиния с храна. За нея има ограничение какво количество храна ще поеме – максимум 10 единици (по този начин усложняваме задачата, защото хората трябва да се изчакват!). Кучетата ще нападат чинията в произволен ред. Ако в нея няма храна, кучето се отдръпва, за да даде възможност на човек да добави храна (има continue в цикъла на run метода). Същото вършат и хората – те сготвят храната и гледат купичката. Ако тя е пълна, те се отдръпват и чакат. Поддържат се броячи за броя на активните кучета и активните готвачи. Ако готвачите станат повече от кучетата, някой от готвачите ще спира работата си.

 

public class CP{
  static Dog[] dogs = new Dog[4];
  static Human[] humans = new Human[3];
  static Dish dish = new Dish(dogs.length, humans.length);

  public static void main(String[] args){
    System.out.println("Program running");
    dogs[0] = new Dog("Sharo 1");
    dogs[1] = new Dog("Sharo 2");
    dogs[2] = new Dog("Sharo 3");
    dogs[3] = new Dog("Sharo 4");
    humans[0] = new Human("Ivan1");
    humans[1] = new Human("Ivan2");
    humans[2] = new Human("Ivan3");
    dogs[0].start();
    dogs[1].start();
    humans[0].start();
    humans[1].start();
    dogs[2].start();
    dogs[3].start();
    humans[2].start();
  }
}

class Dish{
  volatile int activeDogsCount;
  volatile int activeCookersCount;
  volatile int amount;

  public Dish(int dogs, int humans){
    this.amount = 0;
    activeDogsCount = dogs;
    activeCookersCount = humans;
  }

  synchronized void add(int amount){
    this.amount += amount;
    this.notifyAll();
  }

  synchronized int get(){
    int result = this.amount;
    this.amount = 0;
    this.notifyAll();
    return result;
  }
}

class Dog extends Thread{
  int stomach;
  String name;
  public Dog(String name){
    this.name = name;
    this.stomach = 0;
  }
  public void run(){
      try{
        while(this.stomach < 100){
          synchronized(CP.dish){
            if(CP.dish.amount==0){
              CP.dish.wait();
              continue;
            }
            this.getFood();
          }
        }        
      }
      catch(InterruptedException e){
        System.out.println(this.name+" will not feed full");
      }
      System.out.println(this.name+" woof!");
      CP.dish.activeDogsCount--;
  }
  void getFood() throws InterruptedException{
    int ate = CP.dish.get();
    this.stomach += ate;
    this.sleep((int)(Math.random()*500)); // eating
    System.out.println(this.name+" burp! Ate = "+ate+", stomach = "+this.stomach);
  }
}

class Human extends Thread{
  String name;
  boolean haveFoodInHands;
  public Human(String name){
    this.name = name;
    this.haveFoodInHands = false;
  }
  public void run(){
    try{
      while(CP.dish.activeDogsCount >= CP.dish.activeCookersCount){
        if(!this.haveFoodInHands) this.cook();
        synchronized(CP.dish){
          if(CP.dish.amount>0){
            CP.dish.wait();
            continue;
          }
          CP.dish.add(10);
          this.haveFoodInHands = false;
          System.out.println(this.name+" added food to dish! Dish amount = "+CP.dish.amount);
        }
      }
    }
    catch(InterruptedException e){
        System.out.println(this.name+" will stop cooking");
    }
    finally{
      System.out.println(this.name+" stopped cooking!");
      CP.dish.activeCookersCount--;
    }
  }
  void cook()  throws InterruptedException{
    this.sleep((int)(Math.random()*500));
    System.out.println(this.name+" food ready...");
  }
}

Задача 1. Почистете кода и го направете по-пригледен.

Задача 2. Потърсете грешки и предложете оптимизации в този и в предишните примери.

 



Добави коментар

Адресът на електронната поща няма да се публикува


*