In a simulation model, a resource represents an entity (or entities) that is/are shared among processes. Each resource has a quantity associated with it that represents the number of (indivisible) units for the resource.
7.1 The resource Structure
(struct resource ( units units-available units-allocated satisfied queue) #:mutable) units : exact-positive-integer? units-available : exact-nonnegative-integer? units-allocated : exact-nonnegative-integer? satisfied : set? queue : set?
the total number of units of the resource.
the number of units of the resource that are currently available, that is, are not currently allocated.
the number of units of the resource that are currently allocated.
a set of resource allocations that are currently satisfied.
a set of resource allocations yet to be satisfied.
The resource structure includes two sets to implement the queues of satisfied allocations, the satisfied field, and the waiting allocatons, the queue field. The following functions provide access to the n field of the respective sets to facilitate data collection. See Chapter 9, Sets for more details.
(request resource #:units (units 1) #:priority (priority 100))
(request resource #:units (units 1) #:priority (priority 100) #:leave #:now)
(request resource #:units (units 1) #:priority (priority 100) #:leave #:at time)
(request resource #:units (units 1) #:priority (priority 100) #:leave #:in delta)
(request resource #:units (units 1) #:priority (priority 100) #:leave #:when event)
(request resource #:units (units 1) #:priority (priority 100) #:leave time)
The process may reneg on the request by using the #:leave keyword. The options for the #:leave keyword are the same as for the schedule macro. Note that specifying #:leave #:in 0.0 will reneg at the current time, but will allow all now events to be executed, which may relinquish the resource(s) required. This is not the same as specifying #:leave #:now, which will reneg immediately, and may be more appropriate than checking the units-available field.
(resource-request resource [ units priority reneg]) → any resource : resource? units : exact-positive-integer? = 1 priority : real? = 0 reneg : any/c = #f
(resource-relinquish resource units) → any resource : resource? units : exact-positive-integer? (resource-relinquish resource) → any resource : resource?
7.2.3 The with-resource Macro
Since the sequence
(request resource #:units units) ... (relinquish resource)
This example extends the simple simulation model of Chapters 5 and 6 by adding attendents to the system. Each customer must interact with an attendant. The two attendants are modeled using a single resource with two units. This means there is a single queue for the two attendants. Again, the output is a simple trace of customer arrivals, attendant acquisitions, and departures.
#lang racket/base ; Example 2 - Resources (require (planet williams/simulation/simulation)) (define n-attendants 2) (define attendant #f) (define (generator n) (for ((i (in-range n))) (wait (random-exponential 4.0)) (schedule #:now (customer i)))) (define-process (customer i) (printf "~a: customer ~a enters~n" (current-simulation-time) i) (request attendant) (printf "~a: customer ~a gets an attendant~n" (current-simulation-time) i) (work (random-flat 2.0 10.0)) (relinquish attendant) (printf "~a: customer ~a leaves~n" (current-simulation-time) i)) (define (run-simulation n) (with-new-simulation-environment (set! attendant (make-resource n-attendants)) (schedule #:at 0.0 (generator n)) (start-simulation))) (run-simulation 10)
Produces the following output.
0.6153910608822503: customer 0 enters
0.6153910608822503: customer 0 gets an attendant
5.599485116393393: customer 1 enters
5.599485116393393: customer 1 gets an attendant
6.411843645405005: customer 2 enters
8.48917994426752: customer 0 leaves
8.48917994426752: customer 2 gets an attendant
10.275428842274628: customer 1 leaves
16.82673428503317: customer 2 leaves
23.525886616767437: customer 3 enters
23.525886616767437: customer 3 gets an attendant
27.18604340910279: customer 3 leaves
32.1644631797164: customer 4 enters
32.1644631797164: customer 4 gets an attendant
33.14558760001698: customer 5 enters
33.14558760001698: customer 5 gets an attendant
39.67682614849173: customer 4 leaves
40.486553934113665: customer 6 enters
40.486553934113665: customer 6 gets an attendant
41.168084930967424: customer 5 leaves
45.72670063299798: customer 6 leaves
46.747675912143016: customer 7 enters
46.747675912143016: customer 7 gets an attendant
49.212327970772435: customer 8 enters
49.212327970772435: customer 8 gets an attendant
50.556538752352886: customer 9 enters
51.46738784004611: customer 8 leaves
51.46738784004611: customer 9 gets an attendant
52.514846525674855: customer 7 leaves
57.02720211166597: customer 9 leaves
The attendant is declared as a global variable. The actual resource is created (and assigned to the global variable) in run-simulation. The actual usage, the request and relinquish calls, are in the customer process.
A few things to note at this point are:
We went back to a simple function for the generator event.
In this example, the only delay waiting for an attendant is for customer 2, which has to wait for one of the attendants to be relinquished before they can interact.