Factory Simulation


The following Ada code is a simple simulation of a just in time manufacturing plant. The simulation uses tasks to simulate individual production lines, with protected objects forming the small inventory areas between production areas.

This is a simple example of tasking and protected types.

-----------------------------------------------------------------------------
-- Factory Package
-- Defines a set of task types and communication buffers for the simulation
-- of a factory using "Just In Time" manufacturing techniques.
-----------------------------------------------------------------------------
   generic

   type Products is (<>);

   package Factory is

      type Buffers is array(Positive range <>) of Products;

      protected type Production_Buffer (Buf_Size : Positive) is
         entry Add_Product(Item : in Products);
         entry Get_Product(Item : out Products);
      private
         Buffer : Buffers(1..Buf_Size);
         Oldest : Positive := 1;
         Newest : Positive := 1;
         Count  : Natural  := 0;
      end Production_Buffer;

      type Buffer_Access is access Production_Buffer;

      task type Producer is
         entry Start(Downstream : in Buffer_Access);
         entry Halt;
      end Producer;

      task type Consumer is
         entry Start(Upstream : in Buffer_Access);
         entry Halt;
      end Consumer;

   end Factory;

   with Ada.Text_Io;

   package body Factory is

      type Counter is array(Products) of Natural;

   --------------
   -- Consumer --
   --------------

      task body Consumer is
         Next_Unit : Products;
         Conbon : Buffer_Access;
         Next_Delay : Duration;
         Got_Product : Boolean;
         Product_Counts : Counter := (others => 0);
      begin
         accept Start (Upstream : in Buffer_Access) do
            Conbon := Upstream;
         end;

      Consumption:
         loop -- Keep on working until shut down
            select
               Conbon.Get_Product(Next_Unit);
               Got_Product := True;
            or
               delay 0.05; -- Detect upstream buffer empty
               Ada.Text_Io.Put_Line("Upstream buffer empty. Waiting.");
               Got_Product := False;
            end select;
            if Got_Product then
               Next_Delay := Duration(Products'Pos(Next_Unit)) * 0.26;
               Ada.Text_Io.Put_Line("Consumed " & Products'Image(Next_Unit));
               Product_Counts(Next_Unit) := Product_Counts(Next_Unit) + 1;
            end if;
            select
               accept Halt;
               Ada.Text_Io.Put_Line("Products Consumed:");
               for Index in Product_Counts'range loop
                  Ada.Text_Io.Put_Line(Products'Image(Index) &
                                       " :" &
                                       Natural'Image(Product_Counts(Index)));
               end loop;
               exit Consumption;
            or
               delay Next_Delay; -- Time required to consume a product
            end select;
         end loop Consumption;
      end Consumer;

   --------------
   -- Producer --
   --------------

      task body Producer is
         Conbon : Buffer_Access;
         Next_Delay : Duration;
      begin
         accept Start(Downstream : in Buffer_Access) do
            Conbon := Downstream;
         end;

      Production_Loop:
         loop -- Keep on producing until factory is shut down.
            for Unit in Products'range loop
               Next_Delay := Duration(Products'Pos(Unit)) * 1.3;
            --            delay Next_Delay; -- Time required to produce a unit.
               select
                  Conbon.Add_Product(Unit);
               or
                  delay 0.03; -- Detect full downstream buffer
                  Ada.Text_Io.Put_Line("Downstream Buffer full." &
                                       " Producer Waiting.");
                  Conbon.Add_Product(Unit);
               end select;
               Ada.Text_Io.Put_Line("Produced " & Products'Image(Unit));
               select
                  accept Halt;
                  exit Production_Loop;
               or
                  delay 0.5; -- Takes 0.5 seconds to produce a unit
               end select;
            end loop;
         end loop Production_Loop;
      end Producer;

   -----------------------
   -- Production_Buffer --
   -----------------------

      protected body Production_Buffer is

      -----------------
      -- Add_Product --
      -----------------

         entry Add_Product (Item : in Products) when Count < Buf_Size is
         begin
            Buffer(Newest) := Item;
            if Newest < Buf_Size then
               Newest := Newest + 1;
            else
               Newest := 1;
            end if;
            Count := Count + 1;
         end Add_Product;

      -----------------
      -- Get_Product --
      -----------------

         entry Get_Product (Item : out Products) when Count > 0 is
         begin
            Item := Buffer(Oldest);
            if Oldest < Buf_Size then
               Oldest := Oldest + 1;
            else
               Oldest := 1;
            end if;
            Count := Count - 1;
         end Get_Product;

      end Production_Buffer;

   end Factory;

-----------------------------------------------------------------------------
-- Factory Manager
-- The Factory_manager procedure defines the factory products,
-- starts the factory, and shuts down the factory.
-----------------------------------------------------------------------------
   with Factory;
   with Ada.Text_Io;

   procedure Factory_Manager is

      type Production_Units is (Sonic_Screwdriver,
                                Stem_Bolt,
                                Phase_Modulator,
                                Warp_Convertor,
                                Subspace_Transducer);

      package Synthesizer is new Factory(Production_Units);
      use Synthesizer;

      Buffer : Buffer_Access := new Production_Buffer(3);

      Federation       : Producer;
      Ferengi_Alliance : Consumer;

   begin

      Federation.Start(Downstream => Buffer);
      Ada.Text_Io.Put_Line("Federation starting production.");

      delay 5.0; -- The Ferengis are a little slow tapping into the
   -- Federation production system today.

      Ferengi_Alliance.Start(Upstream => Buffer);
      Ada.Text_Io.Put_Line("Ferengi Alliance starting consumption.");

      delay 60.0; -- The manager takes a while to recognize the situation

      Federation.Halt;
      Ada.Text_Io.Put_Line("Federation production halted.");

      delay 1.0; -- The manager must be a Ferengi sympathizer.

      Ferengi_Alliance.Halt;
      Ada.Text_Io.Put_Line("Ferengi Alliance leaving sector.");
   end Factory_Manager;

Contributed by: Jim Rogers
Contributed on: May 18, 1999
License: Public Domain

Back