#lang scribble/doc @(require scribble/manual scribblings/icons (for-label scheme/base plot/plot "../simulation-with-graphics.ss")) @title[#:tag "resources"]{Resources} @local-table-of-contents[] In a simulation model, a @deftech{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. @section{The @scheme[resource] Structure} @schemeblock[ (struct resource (_units _units-available _units-allocated _satisfied _queue)) _units : exact-positive-integer? _units-available : natural-number/c _units-allocated : natural-number/c _satisfied : set? _queue : set?] Represents a resource, possibly with multiple allocatable units, in a resource model. When there are insufficient units available to fulfull a resource request, the request is queues until the number of units requested are available. The queued request may include a priority and the process may reneg on the request based on time or the occurance of a specific event. @itemize{ @item{@schemefont{units}---the total number of units of the resource.} @item{@schemefont{units-available}---the number of units of the resource that are currently available, that is, are not currently allocated.} @item{@schemefont{units-allocated}---the number of units of the resource that are currently allocated.} @item{@schemefont{satisfied}---a set of resource allocations that are currently satisfied.} @item{@schemefont{queue}---a set of resource allocations yet to be satisfied.} } @defproc[(make-resource (units exact-positive-integer? 1)) resource?]{ Returns a newly created resource instance with the specified number of @scheme[units]. If @scheme[unit] is not specified, 1 is used.} @subsection{Shortcuts to Resource Set Variables} The @schemefont{resource} structure includes two sets to implement the queues of satisfied allocations, the @schemefont{satisfied} field, and the waiting allocatons, the @schemefont{queue} field. The following functions provide access to the @schemefont{n} field of the respective sets to facilitate data collection. See Chapter 9 Sets for more details. @defproc[(resource-queue-variable-n (resource resource?)) variable?]{ Returns the variable from the @schemefont{n} field of the set in the @schemefont{queue} field of @scheme[resource].} @defproc[(resource-satisfied-variable-n (resource resource?)) variable?]{ Returns the variable from the @schemefont{n} field of the set in the @schemefont{satisfied} field of @scheme[resource].} @section{Requesting and Relinquishing Resources} @subsection{Requesting Resources} @defform*[#:id request #:literals (now at in when) ((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 delay)) (request resource #:units (units 1) #:priority (priority 100) #:leave (when event)) (request resource #:units (units 1) #:priority (priority 100) #:leave time))]{ Requests the specified number of @scheme[units] of @scheme[resource]. If the requested number of @scheme[units] are not available, the request is places in the queue of waiting allocations, in the @schemefont{queue} field, with the specified @scheme[priority]. The process requesting the resource(s) will delay until the resource(s) are available and allocated to the process. It is an error ro request more units of a resource than exist. The process may reneg on the request by using the @schemefont{#:leave} keyword. The options for the @schemefont{#:leave} keyword are the same as for the @scheme[schedule] macro. Note that specifying @schemefont{#: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 @schemefont{#:leave now}, which will reneg immediately, and may be more appropriate than checking the @schemefont{units-available} field.} @defproc*[(((resource-request (resource resource?) (units exact-positive-integer?) (priority real?) (reneg (or/c real? exact?))) any) ((resource-request (resource resource?) (units exact-positive-integer?) (priority real?)) any) ((resource-request (resource resource?) (units exact-positive-integer?)) any) ((resource-request (resource resource?)) any))]{ Functional equivalent to the @scheme[request] macro, which should be used instead. This is used in legacy code to request resources.} @subsection{Relinquishing Resources} @defform*[#:id relinquish #:literals () ((relinquish resource #:units units) (relinquish resource))]{ Relinquishes the specified number of @scheme[units] of @scheme[resource]. If the number of @scheme[units] to relinquish is not specified, then all of the units allocated to the process are released. It is an error to attempt to relinquish more units that the process has allocated.} @defproc*[(((resource-relinquish (resource resource?) (units exact-positive-integer?)) any) ((resource-relinquish (resource resource?)) any))]{ Functional equivalent to the @scheme[relinquish] macro, which should be used instead. This is used in legacy code to request resources.} @subsection{The @scheme[with-resource] Macro} @defform*[#:id with-resource #:literals () ((with-resource (resource units) body ...+) (with-resource (resource) body ...+))]{ Evaluates the @scheme[body] expressions with the specified number of @scheme[units] of @scheme[resource]. Since the sequence @schemeblock[ (request resource #:units units) ... (relinquish resource) ] is by far the most frequent usage of @scheme[request] and @scheme[relinquish], the @scheme[with-resource] macro is provided to simplify this common usage.} @section{Example---Resources} 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. @schememod[ scheme/base (code:comment "Example 2 - Resources") (require (planet williams/simulation/simulation)) (require (planet williams/science/random-distributions)) (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. @verbatim{ 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 @schemefont{attendant} is declared as a global variable. The actual resource is created (and assigned to the global variable) in @schemefont{run-simulation}. The actual usage, the @scheme[request] and @scheme[relinquish] calls, are in the @schemefont{customer} process. A few things to note at this point are: @itemize{ @item{We went back to a simple function for the @schemefont{generator} event.} @item{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.} @item{We explicitly called @scheme[request] and @scheme[relinquish]---mainly to show their usage. We will generally use @scheme[with-resource] in subsequent models.} }