Skip to content

Commit

Permalink
Merge branch 'master' into priority_as_number
Browse files Browse the repository at this point in the history
  • Loading branch information
Krastanov authored Aug 2, 2023
2 parents b21674b + c62a6e5 commit 3b46b15
Show file tree
Hide file tree
Showing 22 changed files with 401 additions and 65 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# News

## v1.1.0 - 2023-08-02

- Start using `Base`'s API: `Base.unlock`, `Base.islocked`, `Base.isready`, `Base.put!`, `Base.take!`. Deprecate `put`, `release`. Moreover, consider using `Base.take!` instead of `Base.get` (which was not deprecated yet, as we decide which semantics to follow). Lastly, `Base.lock` and `Base.trylock` are **not** implement -- they are superficially similar to `request` and `tryrequest`, but have to be explicitly `@yield`-ed.
- Implement `tryrequest` (similar to `Base.trylock`). However, consider also using `Base.isready` and `request` instead of `tryrequest`.

## v1.0.0 - 2023-05-03

- Rename from SimJulia.jl to ConcurrentSim.jl
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ license = "MIT"
desc = "A discrete event process oriented simulation framework."
authors = ["Ben Lauwens and SimJulia and ConcurrentSim contributors"]
repo = "https://github.com/JuliaDynamics/ConcurrentSim.jl.git"
version = "1.0.0"
version = "1.1.0"

[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Expand Down
2 changes: 1 addition & 1 deletion benchmark/old_processes_MM1.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function customer(sim::Simulation, server::Resource, mu::Float64)
yield(request(server))
dt = rand(Exponential(1/mu))
yield(timeout(sim, dt))
yield(release(server))
yield(unlock(server))
end

function customer2(sim::Simulation, server::Resource, mu::Float64)
Expand Down
2 changes: 1 addition & 1 deletion benchmark/processes_MM1.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ end
@yield request(server)
dt = rand(Exponential(1 / mu))
@yield timeout(sim, dt)
@yield release(server)
@yield unlock(server)
end

function test_mm1(n::Float64)
Expand Down
4 changes: 4 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[deps]
ConcurrentSim = "6ed1e86c-fcaf-46a9-97e0-2b26a2cdb499"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
ResumableFunctions = "c5292f4c-5179-55e1-98c5-05642aab7184"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
5 changes: 5 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
using Revise
using Documenter
using ResumableFunctions
using ConcurrentSim

DocMeta.setdocmeta!(ConcurrentSim, :DocTestSetup, :(using ConcurrentSim, ResumableFunctions); recursive=true)

makedocs(
sitename = "ConcurrentSim",
authors = "Ben Lauwens and SimJulia & ConcurrentSim contributors",
strict = true,
doctest = false,
pages = [
"Home" => "index.md",
"Tutorial" => "tutorial.md",
Expand Down
5 changes: 5 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@
```@autodocs
Modules = [ConcurrentSim]
Private = false
```

```@docs
unlock(res::Container; priority::Int=0)
take!(sto::Store, filter::Function=get_any_item; priority::Int=0)
```
95 changes: 58 additions & 37 deletions docs/src/examples/Latency.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,32 @@ In this example we show how to separate the time delay between processes from th
### Load Packages


```julia
```jldoctest 1; output = false
using ConcurrentSim
using ResumableFunctions
import ConcurrentSim.put
import Base.get
import Base: put!, take!
# output
```

### Define Constants


```julia
srand(8710) # set random number seed for reproducibility
```jldoctest 1; output = false
const SIM_DURATION = 100.
const SEND_PERIOD = 5.0
const RECEIVE_PERIOD = 3.0;
nothing # hide
# output
```

### Define Cable model
The `Cable` contains reference to the simulation it is part of, the delay that messages experience, and a store that contains the sent messages


```julia
```jldoctest 1; output = false
mutable struct Cable
env::Simulation
delay::Float64
Expand All @@ -38,79 +42,96 @@ mutable struct Cable
return new(env, delay, Store{String}(env))
end
end;
nothing # hide
# output
```

The latency function is a generator which yields two events: first a `timeout` that represents the transmission delay, then a put event when the message gets stored in the store.


```julia
```jldoctest 1; output = false
@resumable function latency(env::Simulation, cable::Cable, value::String)
@yield timeout(cable.env, cable.delay)
@yield put(cable.store, value)
end;
@yield put!(cable.store, value)
end;
nothing # hide
# output
```

The `put` and `get` functions allow interaction with the cable (note that these are not `@resumable` because they need to return the result of the operation and not the operation itself).
The `put!` and `take!` functions allow interaction with the cable (note that these are not `@resumable` because they need to return the result of the operation and not the operation itself).


```julia
function put(cable::Cable, value::String)
```jldoctest 1; output = false
function put!(cable::Cable, value::String)
@process latency(cable.env, cable, value) # results in the scheduling of all events generated by latency
end
function get(cable::Cable)
get(cable.store) # returns an element stored in the cable store
function take!(cable::Cable); output = false
take!(cable.store) # returns an element stored in the cable store
end;
nothing # hide
# output
```

The `sender` and `receiver` generators yield events to the simulator.


```julia
```jldoctest 1; output = false
@resumable function sender(env::Simulation, cable::Cable)
while true
@yield timeout(env, SEND_PERIOD)
value = "sender sent this at $(now(env))"
put(cable, value)
put!(cable, value)
end
end
@resumable function receiver(env::Simulation, cable::Cable)
while true
@yield timeout(env, RECEIVE_PERIOD)
msg = @yield get(cable)
msg = @yield take!(cable)
println("Received this at $(now(env)) while $msg")
end
end;
nothing # hide
# output
```

Create simulation, register events, and run!


```julia
```jldoctest 1
env = Simulation()
cable = Cable(env, 10.)
@process sender(env, cable)
@process receiver(env, cable)
run(env, SIM_DURATION)
```

Received this at 15.0 while sender sent this at 5.0
Received this at 20.0 while sender sent this at 10.0
Received this at 25.0 while sender sent this at 15.0
Received this at 30.0 while sender sent this at 20.0
Received this at 35.0 while sender sent this at 25.0
Received this at 40.0 while sender sent this at 30.0
Received this at 45.0 while sender sent this at 35.0
Received this at 50.0 while sender sent this at 40.0
Received this at 55.0 while sender sent this at 45.0
Received this at 60.0 while sender sent this at 50.0
Received this at 65.0 while sender sent this at 55.0
Received this at 70.0 while sender sent this at 60.0
Received this at 75.0 while sender sent this at 65.0
Received this at 80.0 while sender sent this at 70.0
Received this at 85.0 while sender sent this at 75.0
Received this at 90.0 while sender sent this at 80.0
Received this at 95.0 while sender sent this at 85.0
# output
Received this at 15.0 while sender sent this at 5.0
Received this at 20.0 while sender sent this at 10.0
Received this at 25.0 while sender sent this at 15.0
Received this at 30.0 while sender sent this at 20.0
Received this at 35.0 while sender sent this at 25.0
Received this at 40.0 while sender sent this at 30.0
Received this at 45.0 while sender sent this at 35.0
Received this at 50.0 while sender sent this at 40.0
Received this at 55.0 while sender sent this at 45.0
Received this at 60.0 while sender sent this at 50.0
Received this at 65.0 while sender sent this at 55.0
Received this at 70.0 while sender sent this at 60.0
Received this at 75.0 while sender sent this at 65.0
Received this at 80.0 while sender sent this at 70.0
Received this at 85.0 while sender sent this at 75.0
Received this at 90.0 while sender sent this at 80.0
Received this at 95.0 while sender sent this at 85.0
```
2 changes: 1 addition & 1 deletion docs/src/examples/mmc.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ service_dist = Exponential(1 / mu) # service time distribution
@yield request(server) # customer starts service
println("Customer $id entered service: ", now(env))
@yield timeout(env, rand(d_s)) # server is busy
@yield release(server) # customer exits service
@yield unlock(server) # customer exits service
println("Customer $id exited service: ", now(env))
end

Expand Down
8 changes: 4 additions & 4 deletions docs/src/examples/ross.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const G = Exponential(MU)
while true
try @yield timeout(env, Inf) catch end
@yield timeout(env, rand(rng, F))
get_spare = get(spares)
get_spare = take!(spares)
@yield get_spare | timeout(env)
if state(get_spare) != ConcurrentSim.idle
@yield interrupt(value(get_spare))
Expand All @@ -46,8 +46,8 @@ const G = Exponential(MU)
end
@yield request(repair_facility)
@yield timeout(env, rand(rng, G))
@yield release(repair_facility)
@yield put(spares, active_process(env))
@yield unlock(repair_facility)
@yield put!(spares, active_process(env))
end
end
Expand All @@ -58,7 +58,7 @@ end
end
for i in 1:S
proc = @process machine(env, repair_facility, spares)
@yield put(spares, proc)
@yield put!(spares, proc)
end
end
Expand Down
2 changes: 1 addition & 1 deletion docs/src/guides/environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ julia> isnothing(active_process(sim))
true
```

An exemplary use case for this is the resource system: If a process function calls `request` to request a `Resource`, the resource determines the requesting process via `active_process`.
An exemplary use case for this is the resource system: If a process function calls `request` to request (lock) a `Resource`, the resource determines the requesting process via `active_process`.

## Miscellaneous

Expand Down
14 changes: 7 additions & 7 deletions docs/src/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ In this section, we’ll briefly introduce ConcurrentSim’s `Resource` class.

We’ll slightly modify our electric vehicle process `car` that we introduced in the last sections.

The car will now drive to a battery charging station (BCS) and request one of its two charging spots. If both of these spots are currently in use, it waits until one of them becomes available again. It then starts charging its battery and leaves the station afterwards:
The car will now drive to a battery charging station (BCS) and request (lock) one of its two charging spots. If both of these spots are currently in use, it waits until one of them becomes available again. It then starts charging its battery and leaves the station afterwards:

```jldoctest
julia> using ResumableFunctions
Expand All @@ -305,14 +305,14 @@ julia> @resumable function car(env::Environment, name::Int, bcs::Resource, drivi
println(name, " starting to charge at ", now(env))
@yield timeout(sim, charge_duration)
println(name, " leaving the bcs at ", now(env))
@yield release(bcs)
@yield unlock(bcs)
end
car (generic function with 1 method)
```

The resource’s `request` function generates an event that lets you wait until the resource becomes available again. If you are resumed, you “own” the resource until you release it.
The resource’s `request` function generates an event that lets you wait until the resource becomes available again. If you are resumed, you “own” the resource until you release it with `unlock`.

You are responsible to call `release` once you are done using the resource. When you release a resource, the next waiting process is resumed and now “owns” one of the resource’s slots. The basic `Resource` sorts waiting processes in a FIFO (first in—first out) way.
You are responsible to call `unlock` once you are done using the resource. When you unlock (release) a resource, the next waiting process is resumed and now “owns” one of the resource’s slots. The basic `Resource` sorts waiting processes in a FIFO (first in—first out) way.

A resource needs a reference to an `Environment` and a capacity when it is created:

Expand All @@ -328,7 +328,7 @@ DocTestSetup = quote
println(name, " starting to charge at ", now(env))
@yield timeout(sim, charge_duration)
println(name, " leaving the bcs at ", now(env))
@yield release(bcs)
@yield unlock(bcs)
end
end
```
Expand All @@ -355,7 +355,7 @@ DocTestSetup = quote
println(name, " starting to charge at ", now(env))
@yield timeout(sim, charge_duration)
println(name, " leaving the bcs at ", now(env))
@yield release(bcs)
@yield unlock(bcs)
end
sim = Simulation()
Expand Down Expand Up @@ -397,7 +397,7 @@ DocTestSetup = quote
println(name, " starting to charge at ", now(env))
@yield timeout(sim, charge_duration)
println(name, " leaving the bcs at ", now(env))
@yield release(bcs)
@yield unlock(bcs)
end
sim = Simulation()
Expand Down
8 changes: 4 additions & 4 deletions src/ConcurrentSim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ module ConcurrentSim
using Dates
using ResumableFunctions

import Base.run, Base.isless, Base.show, Base.yield, Base.get
import Base.(&), Base.(|)
import Dates.now
import Base: run, isless, show, yield, get, put!, take!, isready, islocked, unlock, lock, trylock, &, |
import Dates: now

export AbstractEvent, Environment, value, state, environment
export Event, succeed, fail, @callback, remove_callback
Expand All @@ -18,7 +17,7 @@ module ConcurrentSim
export @resumable, @yield
export AbstractProcess, Simulation, run, now, active_process, StopSimulation
export Process, @process, interrupt
export Container, Resource, Store, put, get, request, release, cancel
export Container, Resource, Store, put!, get, cancel, request, tryrequest
export nowDatetime

include("base.jl")
Expand All @@ -30,4 +29,5 @@ module ConcurrentSim
include("resources/containers.jl")
include("resources/stores.jl")
include("utils/time.jl")
include("deprecated.jl")
end
4 changes: 4 additions & 0 deletions src/deprecated.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Base.@deprecate put(args...) put!(args...)
#Base.@deprecate request(args...; kwargs...) lock(args...; kwargs...) # Not the same: `request` needs to be yielded, while `lock` yields itself
#Base.@deprecate tryrequest(args...; kwargs...) trylock(args...; kwargs...) # Not the same: `request` needs to be yielded, while `lock` yields itself
Base.@deprecate release(args...; kwargs...) unlock(args...; kwargs...)
Loading

0 comments on commit 3b46b15

Please sign in to comment.