Process Interaction¶
The Process
instance that is returned by the constructor Process(env, func)
can be utilized for process interactions. The two most common examples for this are to wait for another process to finish and to Interrupt another process while it is waiting for an event.
Waiting for a Process¶
As it happens, a SimJulia Process
can be used like an event (technically, a Process
is a subtype of AbstractEvent
). If you yield it, you are resumed once the process has finished. Imagine a car-wash simulation where cars enter the car-wash and wait for the washing process to finish. Or an airport simulation where passengers have to wait until a security check finishes.
Assume that the car from the last example magically became an electric vehicle. Electric vehicles usually take a lot of time charging their batteries after a trip. They have to wait until their battery is charged before they can start driving again.
This can be modeled with an additional charge process. Therefore, two process functions are created: car(env)
and charge(env, duration)
.
A new charge process is started every time the vehicle starts parking. By yielding the Process
instance that Process(env, func, args...)
returns, the run process starts waiting for it to finish:
julia> using SimJulia
julia> function car(env::Environment)
while true
println("Start parking and charging at $(now(env))")
charge_duration = 5.0
charge_proc = Process(env, charge, charge_duration)
yield(charge_proc)
println("Start driving at $(now(env))")
trip_duration = 2.0
yield(Timeout(env, trip_duration))
end
end
car (generic function with 1 method)
julia> function charge(env::Environment, duration::Float64)
yield(Timeout(env, duration))
end
charge (generic function with 1 method)
Starting the simulation is straightforward again: create an environment, one (or more) cars and finally call run(env, 15.0)
:
julia> env = Environment()
Environment(0.0,PriorityQueue{BaseEvent,EventKey}(),0,0,Nullable{Process}())
julia> Process(env, car)
SimJulia.Process 1: car
julia> run(env, 15.0)
Start parking and charging at 0.0
Start driving at 5.0
Start parking and charging at 7.0
Start driving at 12.0
Start parking and charging at 14.0
Interrupting Another Process¶
Imagine, you don’t want to wait until your electric vehicle is fully charged but want to interrupt the charging process and just start driving instead.
SimJulia allows you to interrupt a running process by calling the constructor Interrupt(proc)
that returns an interrupt event.
An interrupt is thrown into process functions as an InterruptException
that can (should) be handled by the interrupted process. The process can than decide what to do next (e.g., continuing to wait for the original event or yielding a new event):
julia> using SimJulia
julia> function driver(env::Environment, car_proc::Process)
yield(Timeout(env, 3.0))
yield(Interrupt(car_proc))
end
driver (generic function with 1 method)
julia> function car(env::Environment)
while true
println("Start parking and charging at $(now(env))")
charge_duration = 5.0
charge_proc = Process(env, charge, charge_duration)
try
yield(charge_proc)
catch exc
println("Was interrupted. Hopefully, the battery is full enough ...")
end
println("Start driving at $(now(env))")
trip_duration = 2.0
yield(Timeout(env, trip_duration))
end
end
car (generic function with 1 method)
julia> function charge(env::Environment, duration::Float64)
yield(Timeout(env, duration))
end
charge (generic function with 1 method)
When you compare the output of this simulation with the previous example, you’ll notice that the car now starts driving at time 3
instead of 5
:
julia> env = Environment()
Environment(0.0,PriorityQueue{BaseEvent,EventKey}(),0,0,Nullable{Process}())
julia> proc = Process(env, car)
SimJulia.Process 1: car
julia> Process(env, driver, proc)
SimJulia.Process 3: driver
julia> run(env, 15.0)
Start parking and charging at 0.0
Was interrupted. Hopefully, the battery is full enough ...
Start driving at 3.0
Start parking and charging at 5.0
Start driving at 10.0
Start parking and charging at 12.0