Processes

Processes are typical event sequences running as asynchronous tasks.

Process Setup

To setup a process, you

  1. implement it in a function taking a Clock variable as its first argument,
  2. wrap it into Prc and start it as an asynchronous task with process!. The @process macro does this in one call.
DiscreteEvents.PrcType
Prc(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 function f(clk, arg...; kw...), must take clk (a Clock) as its first argument,
  • arg...: further arguments to f
  • kw...: keyword arguments to f

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 is identified dynamically!

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!Function
process!([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 overrides spawn,
  • spawn::Bool=false: if true, the process may be scheduled on another thread in parallel and registered to the thread specific clock.
DiscreteEvents.@processMacro
@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!Function
delay!(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 or Distribution,
  • T::Timing: only until is accepted,
  • t: time delay, Number or Distribution.
DiscreteEvents.@delayMacro
@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!Function
wait!(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.@waitMacro
@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.PrcExceptionType
PrcException(event, value)

An exception to be thrown at processes.

Arguments, fields

  • event: deliver an event to the interrupted task
  • value: deliver some other value

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!Function
now!(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.printMethod
print(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.printlnMethod
println(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.