7.5 Sharing a Resource

In the previous queueing situations, at each station there was one resource that was used during the service operation. It is often the case that a resource can be shared across multiple activities. For example, suppose a worker is assigned to attend two machining processes. The resource is said to be shared.

Figure 7.7 illustrates this notion of sharing a resource between two activities. Notice that in the figure, there are two queues, one each for the two different types of parts. If there had been only a single queue to hold both parts, the modeling is very similar to the single queue station modeling that has already been presented. With only one queue, we would need to use a queue discipline to order the parts in the queue and to schedule the end of service according to the appropriate service time distribution for the given part. In the case of two queues, we need to determine how the resource will select the queue in addition to the queue discipline. For the sake of simplicity, let us assume that the queue discipline is first in first out (FIFO). Then, in the case of two queues, we need a mechanism or rule to determine which queue will be processed first, when the resource becomes available.

A Resource Shared Between Two Activities

Figure 7.7: A Resource Shared Between Two Activities

How many events are there for the situation in Figure 7.7? From the strict definition of an event, there are six events in this situation. There are the two arrival events for each type of part. There are two different begin service events and two different end service events. From an implementation perspective, we could model this situation with only two events. We can have a single event that handles both types of arrivals and a single end service event that handles the departure of either type of part. The reason we only need one end service event is because the begin service event logic can be incorporated in the end of service event because whenever a service completes a waiting part will start into service. How many events should you use in your modeling? You should implement the events in a way that facilitates your perspective and your modeling. The trade-off is that when the event logic is consolidated, the logic may be more complicated.

The following listing presents the constructor for the shared queue example. Notice that two instances of the Queue and EventGenerator classes are used. The two event generators are used to implement the arrival processes for the two types of parts. The two queues are used to hold the two types of parts. An instance of SResource is used to represent the workers that are shared between the two activities. The activity times are represented by two RandomVariable instances. A TimeWeighted instance and a ResponseVariable instance are used to collect statistics on the number of parts in the system and the time spent in the system, respectively.

public class SharedResource extends SchedulingElement {

    private final EventGenerator myTypeAGenerator;
    private final EventGenerator myTypeBGenerator;
    private final TimeWeighted myNumInSystem;
    private final ResponseVariable mySystemTime;
    private final SResource myServers;
    private final Queue<QObject> myTypeAWaitingQ;
    private final Queue<QObject> myTypeBWaitingQ;
    private final EndServiceEventAction myEndServiceEventAction;
    private final RandomVariable myServiceRVTypeA;
    private final RandomVariable myServiceRVTypeB;
    
    public SharedResource(ModelElement parent, int numServers, RVariableIfc tbaA,
                          RVariableIfc tbaB, RVariableIfc stA, RVariableIfc stB, String name) {
        super(parent, name);
        myTypeAGenerator = new EventGenerator(this, new TypeAArrivals(), tbaA, tbaA);
        myTypeBGenerator = new EventGenerator(this, new TypeBArrivals(), tbaB, tbaB);
        myServiceRVTypeA = new RandomVariable(this, stA, "Service RV A");
        myServiceRVTypeB = new RandomVariable(this, stB, "Service RV B");
        myServers = new SResource(this, numServers, "Servers");
        myTypeAWaitingQ = new Queue<>(this, getName() + "_QA");
        myTypeBWaitingQ = new Queue<>(this, getName() + "_QB");
        mySystemTime = new ResponseVariable(this, "System Time");
        myNumInSystem = new TimeWeighted(this, "Num in System");
        myEndServiceEventAction = new EndServiceEventAction();
    }

The following listing presents the arrivals of the parts via the generator listeners and the beginning of service. In line 5, the number of parts is incremented. Then, in line 6, the arriving part is represented with a new QObject, which is immediately enqueued. The if statement starting at line 7, checks if the resource has available units and if so, begins serving the next part. In the serveNext() method, the two queues are checked. Notice that the queue for type A parts is checked first. If the queue is not empty, then the part is removed and started into service using the service time distribution for type A parts. If there are no type A parts, the queue for type B parts is checked in a similar fashion. Because the type A queue is checked first, it will have priority over the type B part queue.

    private class TypeAArrivals implements EventGeneratorActionIfc {

        @Override
        public void generate(EventGenerator generator, JSLEvent event) {
            myNumInSystem.increment();
            myTypeAWaitingQ.enqueue(new QObject(getTime()));
            if (myServers.hasAvailableUnits()) { // server available
                serveNext();
            }
        }

    }

    private class TypeBArrivals implements EventGeneratorActionIfc {

        @Override
        public void generate(EventGenerator generator, JSLEvent event) {
            myNumInSystem.increment();
            myTypeBWaitingQ.enqueue(new QObject(getTime()));
            if (myServers.hasAvailableUnits()) { // server available
                serveNext();
            }
        }

    }

    private void serveNext() {
        //logic to choose next from queues
        // if both have waiting parts, assume part type A has priority
        if (myTypeAWaitingQ.isNotEmpty()) {
            QObject partA = myTypeAWaitingQ.removeNext(); //remove the next customer
            myServers.seize();
            // schedule end of service
            scheduleEvent(myEndServiceEventAction, myServiceRVTypeA, partA);
        } else if (myTypeBWaitingQ.isNotEmpty()) {
            QObject partB = myTypeBWaitingQ.removeNext(); //remove the next customer
            myServers.seize();
            // schedule end of service
            scheduleEvent(myEndServiceEventAction, myServiceRVTypeB, partB);
        }
    }

The following code listing presents the end of service event logic for the shared resource example. The end of service logic is very similar to logic that we have seen for the departure from a queueing station. In the end of service action, the part that is leaving is passed to the outer class for statistical collection in the departingSystem() method. The resource is released and the queues are checked to see if a part is waiting. Note that both queues are checked, such that if either queue has a waiting part, the logic for serving the next part is invoked.

    private boolean checkQueues() {
        return (myTypeAWaitingQ.isNotEmpty() || myTypeBWaitingQ.isNotEmpty());
    }

    private class EndServiceEventAction implements EventActionIfc<QObject> {

        @Override
        public void action(JSLEvent<QObject> event) {
            QObject leavingPart = event.getMessage();
            myServers.release();
            if (checkQueues()) { // queue is not empty
                serveNext();
            }
            departSystem(leavingPart);
        }
    }

    private void departSystem(QObject leavingPart) {
        mySystemTime.setValue(getTime() - leavingPart.getCreateTime());
        myNumInSystem.decrement(); // part left system      
    }

Finally, the following code shows how to setup and run the example. The system is configured with the time between arrivals for type A parts and type B parts having exponential distributions with means of 4 and 6 time units, respectively. The service time distributions are also exponential with means of 3 and 5, respectively for type A and B parts. The capacity of the resource is set at 2 workers.

    public static void main(String[] args) {
        Simulation sim = new Simulation("Shared Resource Example");
        // get the model
        Model m = sim.getModel();
        // add to the main model
        RVariableIfc tbaA = new ExponentialRV(4.0);
        RVariableIfc tbaB = new ExponentialRV(6.0);
        RVariableIfc stA = new ExponentialRV(3.0);
        RVariableIfc stB = new ExponentialRV(5.0);
        SharedResource sr = new SharedResource(m, 2, tbaA, tbaB, stA, stB, "SR");
        // set the parameters of the experiment
        sim.setNumberOfReplications(30);
        sim.setLengthOfReplication(20000.0);
        sim.setLengthOfWarmUp(5000.0);
        SimulationReporter r = sim.makeSimulationReporter();
        System.out.println("Simulation started.");
        sim.run();
        System.out.println("Simulation completed.");
        r.printAcrossReplicationSummaryStatistics();
    }

The results indicate that the type B parts wait significantly longer on average than the type A parts. It should be apparent that with some additional design that the shared resource example could be generalized into a class that could be used in other simulation models similar to how the single station queue has been generalized. This is one of the important advantages of an object-oriented approach to simulation modeling.

Number of Replications: 30
Length of Warm up period: 5000.0
Length of Replications: 20000.0
---------------------------------------------------------------------
----
Response Variables
---------------------------------------------------------------------
----
Name                              Average       Std. Dev.       Count

---------------------------------------------------------------------
----
Servers_Util                     0.792550        0.015226       30.00
0000
Servers_#Busy Units              1.585100        0.030453       30.00
0000
SR_QA : Number In Q              0.589924        0.044712       30.00
0000
SR_QA : Time In Q                2.361027        0.155425       30.00
0000
SR_QB : Number In Q              1.948387        0.363318       30.00
0000
SR_QB : Time In Q               11.664922        2.087974       30.00
0000
System Time                      9.891819        0.908085       30.00
0000
Num in System                    4.123410        0.413465       30.00
0000
---------------------------------------------------------------------
----