A tandem queue is a sequence of queues that must be visited (in order) to receive service from resources. The following example presents an illustrative situation.
SingleQStation.SingleQStation class uses an instance of the SResource class to represent its resource.SingleQStation class uses an instance of the Queue class.process() function should look very familiar. /**
* Receives the qObject instance for processing. Handle the queuing
* if the resource is not available and begins service for the next customer.
*/
override fun process(arrivingQObject: QObject) {
// enqueue the newly arriving qObject
myWaitingQ.enqueue(arrivingQObject)
if (isResourceAvailable) {
serveNext()
}
}The serveNext() function removes the next customer from the queue, seizes the resource, and schedules the end of processing event for the customer.
/**
* Called to determine which waiting QObject will be served next Determines
* the next customer, seizes the resource, and schedules the end of the
* service.
*/
protected fun serveNext() {
//remove the next customer
val nextCustomer = myWaitingQ.removeNext()!!
myResource.seize()
// schedule end of service, if the customer can supply a value,
// use it otherwise use the processing time RV
schedule(this::endOfProcessing, delayTime(nextCustomer), nextCustomer)
}
/**
* Could be overridden to supply different approach for determining the service delay
*/
protected fun delayTime(qObject: QObject) : Double {
return qObject.valueObject?.value ?: myActivityTimeRV.value
}endOfProcessing() function represents the logic that should occur after the customer completes its use of the resource for the processing time.sendToNextReceiver() will be discussed further within the following slides. /**
* The end of processing event actions. Collect departing statistics and send the qObject
* to its next receiver. If the queue is not empty, continue processing the next qObject.
*/
private fun endOfProcessing(event: KSLEvent<QObject>) {
val leaving: QObject = event.message!!
myResource.release()
if (isQueueNotEmpty) { // queue is not empty
serveNext()
}
sendToNextReceiver(leaving)
}QObjectReceiverIfc interface that promises to allow the receiving of QObjectQObjectReceiverIfc interface is SAM functional interface.QObjectReceiverIfc interface promise to have a receive() function.SingleQStation ClassSingleQStation class extends the Station class, which implements the QObjectReceiverIfc interface.activityTime parameter determines the service time.resource parameter allows the specification of a possibly shared resource. If it is not supplied, one will be created.nextReceiver parameter indicates what object will receive the completed customer.Station ClassdepartuerCollection() is used to collect statistics.exitAction can be used to define additional actions upon departure.sender property is not null, it is used to send the completed object.abstract class Station(parent: ModelElement,
private var nextReceiver: QObjectReceiverIfc = NotImplementedReceiver, name: String? = null
) : ModelElement(parent, name), QObjectReceiverIfc, StationCIfc {
...
protected fun sendToNextReceiver(completedQObject: QObject) {
departureCollection(completedQObject)
exitAction?.onExit(completedQObject)
onExit(completedQObject)
if (sender != null) {
sender!!.send(completedQObject)
} else {
if (completedQObject.sender != null) {
completedQObject.sender!!.send(completedQObject)
} else {
nextReceiver.receive(completedQObject)
}
}
}class TandemQueue(
parent: ModelElement,
name: String? = null
) : ModelElement(parent, name) {
private val myNS: TWResponse = TWResponse(parent = this, name = "${this.name}:NS")
val numInSystem: TWResponseCIfc
get() = myNS
private val mySysTime: Response = Response(parent = this, name = "${this.name}:TotalSystemTime")
val totalSystemTime: ResponseCIfc
get() = mySysTime
private val myNumProcessed: Counter = Counter(parent = this, name = "${this.name}:TotalProcessed")
val totalProcessed: CounterCIfc
get() = myNumProcessed
...SingleQStation class are used to model the queues.ExitSystem() is the receiver for station 2. private val ad = ExponentialRV(6.0, 1)
private val myArrivalGenerator: EventGenerator = EventGenerator(parent = this,
generateAction = this::arrivalEvent, timeUntilFirstRV = ad, timeBtwEventsRV = ad)
private val myStation1: SingleQStation = SingleQStation(parent = this,
activityTime = ExponentialRV(4.0, 2),name = "${this.name}:Station1")
val station1: SingleQStationCIfc
get() = myStation1
private val myStation2: SingleQStation = SingleQStation(parent = this,
activityTime = ExponentialRV(3.0, 3),name = "${this.name}:Station2")
val station2: SingleQStationCIfc
get() = myStation2
init {
myStation1.nextReceiver(myStation2)
myStation2.nextReceiver(ExitSystem())
} private fun arrivalEvent(generator: EventGenerator){
val customer = QObject()
myNS.increment()
myStation1.receive(customer)
}
private inner class ExitSystem : QObjectReceiverIfc {
override fun receive(qObject: QObject) {
mySysTime.value = time - qObject.createTime
myNumProcessed.increment()
myNS.decrement()
}
}
}| Name | Count | Average | Half-Width |
|---|---|---|---|
| TandemQ:NS | 30 | 3.04 | 0.093 |
| TandemQ:TotalSystemTime | 30 | 18.132 | 0.5 |
| TandemQ:Station1:R:NumBusy | 30 | 0.671 | 0.008 |
| TandemQ:Station1:R:Util | 30 | 0.671 | 0.008 |
| TandemQ:Station1:NS | 30 | 2.031 | 0.088 |
| TandemQ:Station1:StationTime | 30 | 12.107 | 0.483 |
| TandemQ:Station1:Q:NumInQ | 30 | 1.359 | 0.081 |
| TandemQ:Station1:Q:TimeInQ | 30 | 8.101 | 0.457 |
| TandemQ:Station2:R:NumBusy | 30 | 0.5 | 0.004 |
| TandemQ:Station2:R:Util | 30 | 0.5 | 0.004 |
| TandemQ:Station2:NS | 30 | 1.01 | 0.023 |
| TandemQ:Station2:StationTime | 30 | 6.029 | 0.135 |
| TandemQ:Station2:Q:NumInQ | 30 | 0.51 | 0.02 |
| TandemQ:Station2:Q:TimeInQ | 30 | 3.042 | 0.12 |
| TandemQ:TotalProcessed | 30 | 2512.667 | 17.41 |
| TandemQ:Station1:NumProcessed | 30 | 2512.7 | 17.535 |
| TandemQ:Station2:NumProcessed | 30 | 2512.667 | 17.41 |
SResource: A simple resource that has 1 or more units that represent its capacity. The units can be seized and released. Statistics on the utilization and number of busy units are automatically reported.
SingleQStation: A station that has a single waiting line for customers to wait in when its associated resource does not have available units. Statistics on time spent at the station, number of customers at the station, and number of customers processed are automatically reported.