Package umontreal.iro.lecuyer.simprocs

Source Code of umontreal.iro.lecuyer.simprocs.Bin


/*
* Class:        Bin
* Description:  corresponds to a pile of identical tokens, and a list of
                 processes waiting for the tokens when the list is empty
* Environment:  Java
* Software:     SSJ
* Copyright (C) 2001  Pierre L'Ecuyer and Université de Montréal
* Organization: DIRO, Université de Montréal
* @author      
* @since

* SSJ is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License (GPL) as published by the
* Free Software Foundation, either version 3 of the License, or
* any later version.

* SSJ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.

* A copy of the GNU General Public License is available at
   <a href="http://www.gnu.org/licenses">GPL licence site</a>.
*/

package umontreal.iro.lecuyer.simprocs;

import java.util.ListIterator;
import umontreal.iro.lecuyer.simevents.Simulator;
import umontreal.iro.lecuyer.simevents.Accumulate;
import umontreal.iro.lecuyer.simevents.LinkedListStat;
import umontreal.iro.lecuyer.stat.Tally;
import umontreal.iro.lecuyer.util.PrintfFormat;


/**
* A <TT>Bin</TT> corresponds to a pile of identical tokens, and a list of
* processes waiting for the tokens when the list is empty.
* It is a producer/consumer process synchronization device.
* Tokens can be added to the pile (i.e., <EM>produced</EM>) by the
* method {@link #put put}.
* A process can request tokens from the pile (i.e., <EM>consume</EM>)
* by calling {@link #take take}.
*
* <P>
* The behavior of a <TT>Bin</TT> is somewhat similar to that of a
* {@link Resource}.  Each <TT>Bin</TT> has a single queue of waiting
* processes, with FIFO or LIFO service policy, and
* which can be accessed via the method {@link #waitList waitList}.
* This list actually contains objects of the class {@link UserRecord}.
* Each {@link UserRecord} points to a process
* and contains some additional information.
*
*/
public class Bin  {

   private static final int FIFO  = 1;
   private static final int LIFO  = 2;

    // Variables

        private ProcessSimulator sim;
        private String name;
        private int available = 0;
        private int policy = FIFO;
        private LinkedListStat<UserRecord> waitingList;
        private ListIterator<UserRecord> iter;
        private Accumulate statAvail;
        private boolean stats;
        private double     initStatTime;



   /**
    * Constructs a new bin, initially empty, with
    *    service policy FIFO and linked with the default simulator.
    *
    */
   public Bin()  {
      this ("");
   }


   /**
    * Constructs a new bin, initially empty, with
    *    service policy FIFO and linked with simulator sim.
    * 
    * @param sim Simulator associated to the current variable.
    *
    *
    */
   public Bin(ProcessSimulator sim)  {
      this (sim, "");
   }


   /**
    * Constructs a new bin, initially empty, with service policy FIFO,
    *   identifier <TT>name</TT> and linked with the default simulator.
    * 
    * @param name name associated to the bin
    *
    *
    */
   public Bin (String name)  {
      try {
         ProcessSimulator.initDefault();
         this.sim = (ProcessSimulator)Simulator.getDefaultSimulator();
         waitingList = new LinkedListStat<UserRecord>(sim);
         this.name = name;
         iter = waitingList.listIterator();
         stats = false;
      }
      catch (ClassCastException e) {
         throw new IllegalArgumentException("Wrong default Simulator type");
      }
   }


   /**
    * Constructs a new bin, initially empty, with
    *    service policy FIFO, identifier <TT>name</TT> and linked with simulator sim.
    * 
    * @param sim Simulator associated to the current variable.
    *
    *    @param name name associated to the bin
    *
    */
   public Bin (ProcessSimulator sim, String name)  {
      this.sim = sim;
      waitingList = new LinkedListStat<UserRecord>(sim);
      this.name = name;
      iter = waitingList.listIterator();
      stats = false;
   }


   /**
    * Reinitializes this bin by clearing up its pile of tokens and
    *    its waiting list.
    *    The processes in this list (if any) remain in the same states.
    *
    */
   public void init()  {
      int oldAvail = available;
      waitingList.clear();
      available = 0;
      if (stats) initStat();
   }


   /**
    * Starts or stops collecting statistics on the list returned
    *   by {@link #waitList waitList} for this bin.
    *   If the statistical collection is turned ON, It also constructs (if not yet done)
    *   and initializes an additional statistical
    *   collector of class
    *    {@link umontreal.iro.lecuyer.simevents.Accumulate Accumulate}
    *   for this bin.  This collector will be updated
    *   automatically.  It can be accessed via {@link #statOnAvail statOnAvail}, and
    *    monitors the evolution of the
    *   available tokens of the bin
    *   as a function of time.
    * 
    * @param b <TT>true</TT> to turn statistical collection ON, <TT>false</TT> to turn it OFF
    *
    *
    */
   public void setStatCollecting (boolean b)  {
      if (b) {
         if (stats)
            throw new IllegalStateException ("Already collecting statistics for this resource");
         stats = true;
         waitingList.setStatCollecting (true);
         if (statAvail != null)
            initStat();
         else {
            statAvail = new Accumulate (sim, "StatOnAvail");
            statAvail.update (available);
         }
      }
      else {
         if (stats)
            throw new IllegalStateException ("Not collecting statistics for this resource");
         stats = false;
         waitingList.setStatCollecting (false);
      }
   }


   /**
    * Reinitializes all the statistical collectors for this
    *    bin.  These collectors must exist, i.e.,
    *    {@link #setStatCollecting setStatCollecting}&nbsp;<TT>(true)</TT> must have been invoked earlier for
    *    this bin.
    *
    */
   public void initStat() {
        if (!statsthrow new IllegalStateException (
                               "Not collecting statistics for this resource");
        statAvail.init();
        statAvail.update (available);
        waitingList.initStat();
        initStatTime = sim.time();
   }


   /**
    * Sets the service policy for ordering processes waiting
    *    for tokens on the bin to FIFO (<SPAN  CLASS="textit">first in, first out</SPAN>):
    *    the processes are placed in the
    *    list (and served) according to their order of arrival.
    *
    */
   public void setPolicyFIFO() {
      policy = FIFO;
   }


   /**
    * Sets the service policy for ordering processes waiting
    *    for tokens on the bin to LIFO (<SPAN  CLASS="textit">last in, first out</SPAN>):
    *     the processes are placed in the
    *    list (and served) according to their inverse order of arrival:
    *    the last arrived are served first.
    *
    */
   public void setPolicyLIFO() {
      policy = LIFO;
   }


   /**
    * Returns the number of available tokens for this bin.
    * 
    * @return the number of available tokens
    *
    */
   public int getAvailable()  {
      return available;
   }


   /**
    * The executing process invoking this method requests
    *    <TT>n</TT> tokens from this bin.  If enough tokens are available,
    *    the number of tokens in the bin is reduced by <TT>n</TT> and the
    *    process continues its execution.
    *    Otherwise, the executing process is placed into the
    *    {@link #waitList waitList} list (the queue) for this bin and is suspended
    *    until it can obtain the requested number of tokens.
    * 
    * @param n number of requested tokens
    *
    *
    */
   public void take (int n)  {
        SimProcess p = sim.currentProcess();
        if (n <= available) {
            // The process gets the resource right away.
            available -= n;
            if (stats) {
               statAvail.update (available);
               waitingList.statSojourn().add (0.0);
            }
        }
        else {
            // Not enough units of the resource are available.
            // The process joins the queue waitingList;
            UserRecord record = new UserRecord (n, p, sim.time());
            switch (policy) {
                case FIFO : waitingList.addLast (record); break;
                case LIFO : waitingList.addFirst (record); break;
                default   : throw new IllegalStateException (
                                       "the policy must be LIFO or FIFO");
            }
            p.suspend();
        }
   }


   /**
    * Adds <TT>n</TT> tokens to this bin.
    *   If there are processes waiting for tokens from this bin and
    *   whose requests can now be satisfied, they obtain the tokens and
    *   resume their execution.
    * 
    * @param n number of tokens to put into the bin
    *
    *
    */
   public void put (int n)  {
        available+=n;
        if (stats) statAvail.update (available);
        if (waitingList.size()>0wakeProcess();
   }

   private void wakeProcess() {

        UserRecord record;
        ListIterator<UserRecord> iter = waitingList.listIterator();
        while (iter.hasNext() && available > 0) {
            record=iter.next();
            if (!record.process.isAlive())
                throw new IllegalStateException(
                           "process not alive");
                // The thread for this process is still alive.

            if (record.numUnits <= available) {
                // This request can now be satisfied
                record.process.resume();
                available -= record.numUnits;
                if (stats) statAvail.update (available);
                iter.remove();
            }
        }
    }


   /**
    * Returns the list of {@link UserRecord}
    *    for the processes waiting for tokens from this bin.
    * 
    * @return the list of waiting process user records
    *
    */
   public LinkedListStat waitList()  {
      return waitingList;
   }


   /**
    * Returns the statistical collector for the available tokens
    *   on the bin as a function of time.
    *   This collector exists only if {@link #setStatCollecting setStatCollecting}&nbsp;<TT>(true)</TT>
    *   has been invoked previously.
    * 
    * @return the probe for available tokens
    *
    */
   public Accumulate statOnAvail()  {
      return statAvail;
   }


   /**
    * Returns a string containing a complete statistical report on
    *   this  bin. The method
    * <BR>{@link #setStatCollecting setStatCollecting}&nbsp;<TT>(true)</TT> must have
    *   been invoked previously, otherwise no statistics will have been collected.
    *   The report contains statistics on the available tokens, queue size and
    *   waiting time for this bin.
    * 
    * @return a statistical report for this bin, represented as a string
    *
    */
   public String report()  {

    if (statAvail == null) throw new IllegalStateException ("Asking a report for a bin "
                          +"for which setStatCollecting (true) has not been called");

    Accumulate sizeWait = waitingList.statSize();
    Tally sojWait = waitingList.statSojourn();

    PrintfFormat str = new PrintfFormat();

    str.append ("REPORT ON BIN : ").append (name).append (PrintfFormat.NEWLINE);
    str.append ("   From time : ").append (7, 2, 2, initStatTime);
    str.append ("   to time : ");
    str.append (10,2, 2, sim.time());
    str.append (PrintfFormat.NEWLINE + "                    min        max     average  ");
    str.append ("standard dev.  nb. obs.");

    str.append (PrintfFormat.NEWLINE + "   Available tokens ");
    str.append (8, (int)(statAvail.min()+0.5));
    str.append (11, (int)(statAvail.max()+0.5));
    str.append (12, 3, 2, statAvail.average());

    str.append (PrintfFormat.NEWLINE + "   Queue Size  ");
    str.append (8, (int)(sizeWait.min()+0.5));
    str.append (11, (int)(sizeWait.max()+0.5));
    str.append (12, 3, 2, sizeWait.average());

    str.append (PrintfFormat.NEWLINE + "   Wait    ");
    str.append (12, 3, 2, sojWait.min()).append (' ');
    str.append (10, 3, 2, sojWait.max()).append (' ');
    str.append (11, 3, 2, sojWait.average()).append (' ');
    str.append (10, 3, 2, sojWait.standardDeviation());
    str.append (10, sojWait.numberObs());

    return str.toString();
   }


   /**
    * Returns the current simulator of this continuous-time variable.
    * 
    * @return the current simulator of the variable
    *
    */
   public Simulator simulator()  {
      return sim;
   }


   /**
    * Set the current simulator of this continuous-time variable.
    *  This method must not be called while a simulator is running.
    * 
    * @param sim the simulator of the current variable
    *
    *
    */
   public void setSimulator (ProcessSimulator sim)  {
      this.sim = sim;
   }

}
TOP

Related Classes of umontreal.iro.lecuyer.simprocs.Bin

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.