Skip to content

Commit 8ba37c9

Browse files
committed
MVar: documentation.
1 parent fc5af4f commit 8ba37c9

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

lib/concurrent/mvar.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,39 @@
44

55
module Concurrent
66

7+
# An `MVar` is a single-element container that blocks on `get` if it is empty,
8+
# and blocks on `put` if it is full. It is safe to use an `MVar` from
9+
# multiple threads. `MVar` can be seen as a single-element blocking queue, or
10+
# a rendezvous variable.
11+
#
12+
# An `MVar` is typically used to transfer objects between threads, where the
13+
# sending thread will block if the previous message hasn't been taken yet by the
14+
# receiving thread. It can also be used to control access to some global shared
15+
# state, where threads `take` the value, perform some operation, and then
16+
# `put` it back.
717
class MVar
818

919
include Dereferenceable
1020

21+
# Unique value that represents that an `MVar` was empty
1122
EMPTY = Object.new
23+
24+
# Unique value that represents that an `MVar` timed out before it was able
25+
# to produce a value.
1226
TIMEOUT = Object.new
1327

28+
# Create a new `MVar`, either empty or with an initial value.
29+
#
30+
# @param [Hash] opts the options controlling how the future will be processed
31+
# @option opts [Boolean] :operation (false) when `true` will execute the future on the global
32+
# operation pool (for long-running operations), when `false` will execute the future on the
33+
# global task pool (for short-running tasks)
34+
# @option opts [object] :executor when provided will run all operations on
35+
# this executor rather than the global thread pool (overrides :operation)
36+
# @option opts [String] :dup_on_deref (false) call `#dup` before returning the data
37+
# @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data
38+
# @option opts [String] :copy_on_deref (nil) call the given `Proc` passing the internal value and
39+
# returning the value returned from the proc
1440
def initialize(value = EMPTY, opts = {})
1541
@value = value
1642
@mutex = Mutex.new
@@ -19,6 +45,10 @@ def initialize(value = EMPTY, opts = {})
1945
set_deref_options(opts)
2046
end
2147

48+
# Remove the value from an `MVar`, leaving it empty, and blocking if there
49+
# isn't a value. A timeout can be set to limit the time spent blocked, in
50+
# which case it returns `TIMEOUT` if the time is exceeded.
51+
# @return [Object] the value that was taken, or `TIMEOUT`
2252
def take(timeout = nil)
2353
@mutex.synchronize do
2454
wait_for_full(timeout)
@@ -35,6 +65,10 @@ def take(timeout = nil)
3565
end
3666
end
3767

68+
# Put a value into an `MVar`, blocking if there is already a value until
69+
# it is empty. A timeout can be set to limit the time spent blocked, in
70+
# which case it returns `TIMEOUT` if the time is exceeded.
71+
# @return [Object] the value that was put, or `TIMEOUT`
3872
def put(value, timeout = nil)
3973
@mutex.synchronize do
4074
wait_for_empty(timeout)
@@ -50,6 +84,11 @@ def put(value, timeout = nil)
5084
end
5185
end
5286

87+
# Atomically `take`, yield the value to a block for transformation, and then
88+
# `put` the transformed value. Returns the transformed value. A timeout can
89+
# be set to limit the time spent blocked, in which case it returns `TIMEOUT`
90+
# if the time is exceeded.
91+
# @return [Object] the transformed value, or `TIMEOUT`
5392
def modify(timeout = nil)
5493
raise ArgumentError.new('no block given') unless block_given?
5594

@@ -68,6 +107,7 @@ def modify(timeout = nil)
68107
end
69108
end
70109

110+
# Non-blocking version of `take`, that returns `EMPTY` instead of blocking.
71111
def try_take!
72112
@mutex.synchronize do
73113
if unlocked_full?
@@ -81,6 +121,7 @@ def try_take!
81121
end
82122
end
83123

124+
# Non-blocking version of `put`, that returns whether or not it was successful.
84125
def try_put!(value)
85126
@mutex.synchronize do
86127
if unlocked_empty?
@@ -93,6 +134,7 @@ def try_put!(value)
93134
end
94135
end
95136

137+
# Non-blocking version of `put` that will overwrite an existing value.
96138
def set!(value)
97139
@mutex.synchronize do
98140
old_value = @value
@@ -102,6 +144,7 @@ def set!(value)
102144
end
103145
end
104146

147+
# Non-blocking version of `modify` that will yield with `EMPTY` if there is no value yet.
105148
def modify!
106149
raise ArgumentError.new('no block given') unless block_given?
107150

@@ -117,10 +160,12 @@ def modify!
117160
end
118161
end
119162

163+
# Returns if the `MVar` is currently empty.
120164
def empty?
121165
@mutex.synchronize { @value == EMPTY }
122166
end
123167

168+
# Returns if the `MVar` currently contains a value.
124169
def full?
125170
not empty?
126171
end

0 commit comments

Comments
 (0)