Processes
Processes are typical event sequences running as asynchronous tasks.
Process Setup
To setup a process, you
- implement it in a function taking a
Clock
variable as its first argument, - wrap it into
Prc
and start it as an asynchronous task withprocess!
. The@process
macro does this in one call.
DiscreteEvents.Prc
— TypePrc(id, f, arg...; kw...)
Prc(f, arg...; kw...)
Prepare a function to run as a process and get registered to a clock.
Arguments, Fields
id
: some unique identification for registration,f::Function
: a functionf(clk, arg...; kw...)
, must takeclk
(aClock
) as its first argument,arg...
: further arguments tof
kw...
: keyword arguments tof
Fields identified during registration
id
: if it is not provided, some integer will be calculated for it during registration,task::Union{Task,Nothing}
: a task structure used for diagnosis,clk::Union{AbstractClock,Nothing}
: clock where the process is registered,
The clock clk
where a process runs and gets registered is identified during process startup and then passed as 1st argument to f
.
DiscreteEvents.process!
— Functionprocess!([clk], prc, cycles; <keyword arguments>)
Register a Prc
to a clock, start an asynchronous task executing the process function in a loop and return the id
it was registered with. It can then be found under clk.processes[id]
.
Arguments
c<:AbstractClock
: if not provided, the process runs under𝐶
,prc::Prc
: it contains a function and its arguments,cycles<:Number=Inf
: number of loop cycles the process should run,
Keyword arguments
cid::Int=clk.id
: if cid ≠ clk.id, assign the event to the parallel clock with id == cid. This overridesspawn
,spawn::Bool=false
: if true, the process may be scheduled on another thread in parallel and registered to the thread specific clock.
DiscreteEvents.@process
— Macro@process f(arg...) [cycles]
Create a process from a function f(arg...)
.
Wrap a function and its arguments in a Prc
and start it with process!
.
Arguments
f
: a function,arg...
: arguments, the first argument must be an AbstractClock,cycles::Int
: the number of cycles,f
should run.
Returns
- an
Int
process id.
Delay and Wait …
Functions implementing processes create events implicitly by calling delay!
or wait!
on their clock. They wait for resources to be available by using take!
and put!
on channels. Those calls will suspend an asynchronous task until a given time or until certain conditions are met or requested resources are available.
DiscreteEvents.delay!
— Functiondelay!(clk, Δt)
delay!(clk, T, t)
Delay (suspend) a process for a time interval Δt
on the clock clk
.
Arguments
clk::Clock
,Δt
: time interval,Number
orDistribution
,T::Timing
: onlyuntil
is accepted,t
: time delay,Number
orDistribution
.
DiscreteEvents.@delay
— Macro@delay clk Δt
@delay clk until t
Delay a process on a clock clk
for a time interval Δt
or until a time t
.
DiscreteEvents.wait!
— Functionwait!(clk, cond)
Delay (suspend) a process on a clock clk until a condition has become true.
Arguments
clk::Clock
,cond<:Action
: a condition, true if all expressions or functions therein return true.
DiscreteEvents.@wait
— Macro@wait clk f(arg...)
Conditionally wait on a clock clk
until f(arg...)
returns true.
Interrupts
If other events (e.g. representing reneging customers, failures) interrupt the typical event sequence of a process, it is waiting for a time or condition or resource and not ready to respond to something else. Processes therefore must use exception handling to handle unexpected events.
DiscreteEvents.PrcException
— TypePrcException(event, value)
An exception to be thrown at processes.
Arguments, fields
event
: deliver an event to the interrupted taskvalue
: deliver some other value
DiscreteEvents.interrupt!
— Functioninterrupt!(p::Prc, ev, value)
Interrupt a Prc
by throwing a PrcException
to it.
An example at DiscreteEventsCompanion
illustrates how to handle interrupts to a process. Things can get messy quickly if there are several unusual events which have to be handled in a process.
Now
Processes (or asynchronous tasks in general) transfer IO-operations with a now!
call to the (master) clock to ensure they get executed at current clock time. As a convenience you can print directly to the clock.
DiscreteEvents.now!
— Functionnow!(clk::Clock, ex::A) where {A<:Action}
Transfer an IO-operation ex
to clk
or if it is a parallel clock to the master clock (on thread 1). The clock executes it before proceeding to the next time step.
Base.print
— Methodprint(clk::Clock, [io::IO], x, xs...)
Create a now!
event to a busy clock clk
to print(x, xs...)
to io
(or to stdout
).
If the clock is not busy, x
and xs...
are printed as usual. print(clk)
still prints repr(clk)
.
Base.println
— Methodprintln(clk::Clock, [io::IO], xs...)
Create a now!
event to a busy clock clk
to println(x, xs...)
to io
(or to stdout
).
If the clock is not busy, x
and xs...
are printed as usual. println(clk)
still prints repr(clk)
.
Examples
The A-B Call Center Problem illustrates how to implement and setup a process. You can find more examples at DiscreteEventsCompanion
.