Skip to content

Commit 0c4a592

Browse files
committed
documentation and doctests
1 parent 8682762 commit 0c4a592

File tree

8 files changed

+114
-42
lines changed

8 files changed

+114
-42
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
## v1.0.1 - dev
44

5-
- Start using `Base`'s API: `lock`, `trylock`, `unlock`, `islocked`, `isready`, `get!` and deprecate `get`, `request`, `release`.
5+
- Start using `Base`'s API: `lock`, `trylock`, `unlock`, `islocked`, `isready`, `put!`, `take!`. Deprecate `put`, `request`, `release`. Moreover, consider using `take!` instead of `get` (which was not deprecated as it has numerous internal uses).
6+
67
## v1.0.0 - 2023-05-03
78

89
- Rename from SimJulia.jl to ConcurrentSim.jl

docs/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ ConcurrentSim = "6ed1e86c-fcaf-46a9-97e0-2b26a2cdb499"
33
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
44
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
55
ResumableFunctions = "c5292f4c-5179-55e1-98c5-05642aab7184"
6+
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
67
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Revise
12
using Documenter
23
using ResumableFunctions
34
using ConcurrentSim

docs/src/api.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,11 @@
33
```@autodocs
44
Modules = [ConcurrentSim]
55
Private = false
6+
```
7+
8+
```@docs
9+
lock(res::Container; priority::Int=0)
10+
unlock(res::Container; priority::Int=0)
11+
trylock(res::Container; priority::Int=0)
12+
take!(sto::Store, filter::Function=get_any_item; priority::Int=0)
613
```

docs/src/examples/Latency.md

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,32 @@ In this example we show how to separate the time delay between processes from th
77
### Load Packages
88

99

10-
```julia
10+
```jldoctest 1; output = false
1111
using ConcurrentSim
1212
using ResumableFunctions
13-
import Base: put!, get
13+
import Base: put!, take!
14+
15+
# output
1416
```
1517

1618
### Define Constants
1719

1820

19-
```julia
20-
srand(8710) # set random number seed for reproducibility
21+
```jldoctest 1; output = false
2122
const SIM_DURATION = 100.
2223
const SEND_PERIOD = 5.0
2324
const RECEIVE_PERIOD = 3.0;
25+
26+
nothing # hide
27+
28+
# output
2429
```
2530

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

2934

30-
```julia
35+
```jldoctest 1; output = false
3136
mutable struct Cable
3237
env::Simulation
3338
delay::Float64
@@ -37,35 +42,47 @@ mutable struct Cable
3742
return new(env, delay, Store{String}(env))
3843
end
3944
end;
45+
46+
nothing # hide
47+
48+
# output
4049
```
4150

4251
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.
4352

4453

45-
```julia
54+
```jldoctest 1; output = false
4655
@resumable function latency(env::Simulation, cable::Cable, value::String)
4756
@yield timeout(cable.env, cable.delay)
4857
@yield put!(cable.store, value)
49-
end;
58+
end;
59+
60+
nothing # hide
61+
62+
# output
5063
```
5164

52-
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).
65+
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).
5366

5467

55-
```julia
68+
```jldoctest 1; output = false
5669
function put!(cable::Cable, value::String)
5770
@process latency(cable.env, cable, value) # results in the scheduling of all events generated by latency
5871
end
5972
60-
function get(cable::Cable)
61-
get(cable.store) # returns an element stored in the cable store
73+
function take!(cable::Cable); output = false
74+
take!(cable.store) # returns an element stored in the cable store
6275
end;
76+
77+
nothing # hide
78+
79+
# output
6380
```
6481

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

6784

68-
```julia
85+
```jldoctest 1; output = false
6986
@resumable function sender(env::Simulation, cable::Cable)
7087
while true
7188
@yield timeout(env, SEND_PERIOD)
@@ -77,39 +94,44 @@ end
7794
@resumable function receiver(env::Simulation, cable::Cable)
7895
while true
7996
@yield timeout(env, RECEIVE_PERIOD)
80-
msg = @yield get(cable)
97+
msg = @yield take!(cable)
8198
println("Received this at $(now(env)) while $msg")
8299
end
83100
end;
101+
102+
nothing # hide
103+
104+
# output
84105
```
85106

86107
Create simulation, register events, and run!
87108

88109

89-
```julia
110+
```jldoctest 1
90111
env = Simulation()
91112
cable = Cable(env, 10.)
92113
@process sender(env, cable)
93114
@process receiver(env, cable)
94115
95116
run(env, SIM_DURATION)
96-
```
97-
98-
Received this at 15.0 while sender sent this at 5.0
99-
Received this at 20.0 while sender sent this at 10.0
100-
Received this at 25.0 while sender sent this at 15.0
101-
Received this at 30.0 while sender sent this at 20.0
102-
Received this at 35.0 while sender sent this at 25.0
103-
Received this at 40.0 while sender sent this at 30.0
104-
Received this at 45.0 while sender sent this at 35.0
105-
Received this at 50.0 while sender sent this at 40.0
106-
Received this at 55.0 while sender sent this at 45.0
107-
Received this at 60.0 while sender sent this at 50.0
108-
Received this at 65.0 while sender sent this at 55.0
109-
Received this at 70.0 while sender sent this at 60.0
110-
Received this at 75.0 while sender sent this at 65.0
111-
Received this at 80.0 while sender sent this at 70.0
112-
Received this at 85.0 while sender sent this at 75.0
113-
Received this at 90.0 while sender sent this at 80.0
114-
Received this at 95.0 while sender sent this at 85.0
115117
118+
# output
119+
120+
Received this at 15.0 while sender sent this at 5.0
121+
Received this at 20.0 while sender sent this at 10.0
122+
Received this at 25.0 while sender sent this at 15.0
123+
Received this at 30.0 while sender sent this at 20.0
124+
Received this at 35.0 while sender sent this at 25.0
125+
Received this at 40.0 while sender sent this at 30.0
126+
Received this at 45.0 while sender sent this at 35.0
127+
Received this at 50.0 while sender sent this at 40.0
128+
Received this at 55.0 while sender sent this at 45.0
129+
Received this at 60.0 while sender sent this at 50.0
130+
Received this at 65.0 while sender sent this at 55.0
131+
Received this at 70.0 while sender sent this at 60.0
132+
Received this at 75.0 while sender sent this at 65.0
133+
Received this at 80.0 while sender sent this at 70.0
134+
Received this at 85.0 while sender sent this at 75.0
135+
Received this at 90.0 while sender sent this at 80.0
136+
Received this at 95.0 while sender sent this at 85.0
137+
```

docs/src/examples/ross.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const G = Exponential(MU)
3737
while true
3838
try @yield timeout(env, Inf) catch end
3939
@yield timeout(env, rand(rng, F))
40-
get_spare = get(spares)
40+
get_spare = take!(spares)
4141
@yield get_spare | timeout(env)
4242
if state(get_spare) != ConcurrentSim.idle
4343
@yield interrupt(value(get_spare))

src/resources/containers.jl

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@ struct ContainerKey{N<:Real} <: ResourceKey
44
amount :: N
55
end
66

7+
"""
8+
Container{N}(env::Environment, capacity::N=one(N); level::N=zero(N))
9+
10+
A "Container" resource object, storing up to `capacity` units of a resource (of type `N`).
11+
12+
There is a `Resource` alias for `Container{Int}`.
13+
14+
`Resource()` with default capacity of `1` is very similar to a typical lock.
15+
The [`lock`](@ref), [`unlock`](@ref), and [`trylock`](@ref) functions are a convenient way to interact with such a "lock",
16+
in a way mostly compatible with other discrete event and concurrency frameworks.
17+
18+
See [`Store`](@ref) for a more channel-like resource.
19+
20+
Think of `Resource` and `Container` as locks and of `Store` as channels. They block only if empty (on taking) or full (on storing).
21+
"""
722
mutable struct Container{N<:Real} <: AbstractResource
823
env :: Environment
924
capacity :: N
@@ -30,7 +45,12 @@ function put!(con::Container{N}, amount::N; priority::Int=0) where N<:Real
3045
put_ev
3146
end
3247

33-
lock(res::Resource; priority::Int=0) = put!(res, 1; priority=priority)
48+
"""
49+
lock(res::Container)
50+
51+
Locks the Container and return the lock event.
52+
"""
53+
lock(res::Container; priority::Int=0) = put!(res, 1; priority=priority)
3454

3555
"""
3656
trylock(res::Resource)
@@ -51,7 +71,7 @@ julia> trylock(res)
5171
false
5272
```
5373
"""
54-
function trylock(res::Resource; priority::Int=0)
74+
function trylock(res::Container; priority::Int=0)
5575
islocked(res) && return false # TODO check priority
5676
lock(res; priority)
5777
end
@@ -64,7 +84,12 @@ function get(con::Container{N}, amount::N; priority::Int=0) where N<:Real
6484
get_ev
6585
end
6686

67-
unlock(res::Resource; priority::Int=0) = get(res, 1; priority=priority)
87+
"""
88+
unlock(res::Container)
89+
90+
Unlocks the Container and return the unlock event.
91+
"""
92+
unlock(res::Container; priority::Int=0) = get(res, 1; priority=priority)
6893

6994
function do_put(con::Container{N}, put_ev::Put, key::ContainerKey{N}) where N<:Real
7095
con.level + key.amount > con.capacity && return false

src/resources/stores.jl

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ struct StoreGetKey <: ResourceKey
1111
filter :: Function
1212
end
1313

14+
"""
15+
Store{T}(env::Environment; capacity::UInt=typemax(UInt))
16+
17+
A store is a resource that can hold a number of items of type `T`. It is similar to a `Base.Channel` with a finite capacity ([`put!`](@ref) blocks after reaching capacity).
18+
The [`put!`](@ref) and [`take!`](@ref) functions are a convenient way to interact with such a "channel" in a way mostly compatible with other discrete event and concurrency frameworks.
19+
20+
See [`Container`](@ref) for a more lock-like resource.
21+
22+
Think of `Resource` and `Container` as locks and of `Store` as channels. They block only if empty (on taking) or full (on storing).
23+
"""
1424
mutable struct Store{T} <: AbstractResource
1525
env :: Environment
1626
capacity :: UInt
@@ -24,6 +34,11 @@ mutable struct Store{T} <: AbstractResource
2434
end
2535
end
2636

37+
"""
38+
put!(sto::Store, item::T)
39+
40+
Put an item into the store. Returns the put event, blocking if the store is full.
41+
"""
2742
function put!(sto::Store{T}, item::T; priority::Int=0) where T
2843
put_ev = Put(sto.env)
2944
sto.put_queue[put_ev] = StorePutKey{T}(priority, sto.seid+=one(UInt), item)
@@ -100,13 +115,13 @@ true
100115
"""
101116
islocked(sto::Store) = sto.load==sto.capacity
102117

103-
unlock(::Store) = error("There is no well defined way to \"unlock\" a store. Instead of attempting `unlock` consider using `pop!(::Store)` or use a `Resource` instead of a `Store`.")
104-
lock(::Store) = error("There is no well defined way to \"lock\" a store. Instead of attempting `lock` consider using `put!(::Store, ...)` or use a `Resource` instead of a `Store`.")
105-
trylock(::Store) = error("There is no well defined way to \"lock\" a store. Instead of attempting `lock` consider using `put!(::Store, ...)` or use a `Resource` instead of a `Store`.")
118+
unlock(::Store) = error("There is no well defined way to \"unlock\" a Store without taking an element out of it. Instead of attempting `unlock` consider using `take!(::Store)` or use a `Resource` instead of a `Store`. Think of `Resource` and `Container` as locks and of `Store` as channels. They block only if empty (on taking) or full (on storing).")
119+
lock(::Store) = error("There is no well defined way to \"lock\" a Store without storing an element in it. Instead of attempting `lock` consider using `put!(::Store, ...)` or use a `Resource` instead of a `Store`. Think of `Resource` and `Container` as locks and of `Store` as channels. They block only if empty (on taking) or full (on storing).")
120+
trylock(::Store) = error("There is no well defined way to \"lock\" a Store without storing an element in it. Instead of attempting `lock` consider using `put!(::Store, ...)` or use a `Resource` instead of a `Store`. Think of `Resource` and `Container` as locks and of `Store` as channels. They block only if empty (on taking) or full (on storing).")
106121

107122
"""
108123
take!(::Store)
109124
110125
An alias for `get(::Store)` for easier interoperability with the `Base.Channel` interface. Blocks if the store is empty.
111126
"""
112-
take!(sto::Store{T}, filter::Function=get_any_item; priority::Int=0) where {T} = get(sto, filter; priority)
127+
take!(sto::Store, filter::Function=get_any_item; priority::Int=0) = get(sto, filter; priority)

0 commit comments

Comments
 (0)