Skip to content

Commit 6cfac83

Browse files
committed
Dereferenceable uses synchronization layer.
1 parent 072083c commit 6cfac83

File tree

7 files changed

+32
-43
lines changed

7 files changed

+32
-43
lines changed

lib/concurrent/concern/dereferenceable.rb

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@ module Concern
99
#
1010
# @!macro copy_options
1111
module Dereferenceable
12+
# NOTE: This module is going away in 2.0. In the mean time we need it to
13+
# play nicely with the synchronization layer. This means that the
14+
# including class SHOULD be synchronized and it MUST implement a
15+
# `#synchronize` method. Not doing so will lead to runtime errors.
1216

1317
# Return the value this object represents after applying the options specified
1418
# by the `#set_deref_options` method.
1519
#
1620
# @return [Object] the current value of the object
1721
def value
18-
mutex.synchronize { apply_deref_options(@value) }
22+
synchronize { apply_deref_options(@value) }
1923
end
2024
alias_method :deref, :value
2125

@@ -25,43 +29,24 @@ def value
2529
#
2630
# @param [Object] value the new value
2731
def value=(value)
28-
mutex.synchronize{ @value = value }
29-
end
30-
31-
# A mutex lock used for synchronizing thread-safe operations. Methods defined
32-
# by `Dereferenceable` are synchronized using the `Mutex` returned from this
33-
# method. Operations performed by the including class that operate on the
34-
# `@value` instance variable should be locked with this `Mutex`.
35-
#
36-
# @return [Mutex] the synchronization object
37-
def mutex
38-
@mutex
39-
end
40-
41-
# Initializes the internal `Mutex`.
42-
#
43-
# @note This method *must* be called from within the constructor of the including class.
44-
#
45-
# @see #mutex
46-
def init_mutex(mutex = Mutex.new)
47-
@mutex = mutex
32+
synchronize{ @value = value }
4833
end
4934

5035
# @!macro [attach] dereferenceable_set_deref_options
5136
# Set the options which define the operations #value performs before
5237
# returning data to the caller (dereferencing).
53-
#
38+
#
5439
# @note Most classes that include this module will call `#set_deref_options`
5540
# from within the constructor, thus allowing these options to be set at
5641
# object creation.
57-
#
42+
#
5843
# @param [Hash] opts the options defining dereference behavior.
5944
# @option opts [String] :dup_on_deref (false) call `#dup` before returning the data
6045
# @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data
6146
# @option opts [String] :copy_on_deref (nil) call the given `Proc` passing
6247
# the internal value and returning the value returned from the proc
6348
def set_deref_options(opts = {})
64-
mutex.synchronize{ ns_set_deref_options(opts) }
49+
synchronize{ ns_set_deref_options(opts) }
6550
end
6651

6752
# @!macro dereferenceable_set_deref_options

lib/concurrent/concern/obligation.rb

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ module Concern
99

1010
module Obligation
1111
include Concern::Dereferenceable
12+
# NOTE: The Dereferenceable module is going away in 2.0. In the mean time
13+
# we need it to place nicely with the synchronization layer. This means
14+
# that the including class SHOULD be synchronized and it MUST implement a
15+
# `#synchronize` method. Not doing so will lead to runtime errors.
1216

1317
# Has the obligation been fulfilled?
1418
#
@@ -104,7 +108,7 @@ def value!(timeout = nil)
104108
#
105109
# @return [Symbol] the current state
106110
def state
107-
mutex.synchronize { @state }
111+
synchronize { @state }
108112
end
109113

110114
# If an exception was raised during processing this will return the
@@ -113,7 +117,7 @@ def state
113117
#
114118
# @return [Exception] the exception raised during processing or `nil`
115119
def reason
116-
mutex.synchronize { @reason }
120+
synchronize { @reason }
117121
end
118122

119123
# @example allows Obligation to be risen
@@ -132,8 +136,7 @@ def get_arguments_from(opts = {})
132136
end
133137

134138
# @!visibility private
135-
def init_obligation(*args)
136-
init_mutex(*args)
139+
def init_obligation
137140
@event = Event.new
138141
end
139142

@@ -155,20 +158,20 @@ def set_state(success, value, reason)
155158

156159
# @!visibility private
157160
def state=(value)
158-
mutex.synchronize { ns_set_state(value) }
161+
synchronize { ns_set_state(value) }
159162
end
160163

161164
# Atomic compare and set operation
162165
# State is set to `next_state` only if `current state == expected_current`.
163166
#
164167
# @param [Symbol] next_state
165168
# @param [Symbol] expected_current
166-
#
169+
#
167170
# @return [Boolean] true is state is changed, false otherwise
168171
#
169172
# @!visibility private
170173
def compare_and_set_state(next_state, *expected_current)
171-
mutex.synchronize do
174+
synchronize do
172175
if expected_current.include? @state
173176
@state = next_state
174177
true
@@ -184,7 +187,7 @@ def compare_and_set_state(next_state, *expected_current)
184187
#
185188
# @!visibility private
186189
def if_state(*expected_states)
187-
mutex.synchronize do
190+
synchronize do
188191
raise ArgumentError.new('no block given') unless block_given?
189192

190193
if expected_states.include? @state

lib/concurrent/delay.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def reconfigure(&block)
155155
protected
156156

157157
def ns_initialize(opts, &block)
158-
init_obligation(self)
158+
init_obligation
159159
set_deref_options(opts)
160160
@executor = opts[:executor]
161161

lib/concurrent/ivar.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def try_set(value = NULL, &block)
153153
# @!visibility private
154154
def ns_initialize(value, opts)
155155
value = yield if block_given?
156-
init_obligation(self)
156+
init_obligation
157157
self.observers = Collection::CopyOnWriteObserverSet.new
158158
set_deref_options(opts)
159159

lib/concurrent/mvar.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,12 @@ def full?
200200
!empty?
201201
end
202202

203+
protected
204+
205+
def synchronize(&block)
206+
@mutex.synchronize(&block)
207+
end
208+
203209
private
204210

205211
def unlocked_empty?

lib/concurrent/timer_task.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,6 @@ def timeout_interval=(value)
271271
private
272272

273273
def ns_initialize(opts, &task)
274-
init_mutex(self)
275274
set_deref_options(opts)
276275

277276
self.execution_interval = opts[:execution] || opts[:execution_interval] || EXECUTION_INTERVAL

spec/concurrent/concern/obligation_spec.rb

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,9 @@ module Concern
55

66
let (:obligation_class) do
77

8-
Class.new do
8+
Class.new(Synchronization::LockableObject) do
99
include Obligation
10-
11-
def initialize
12-
init_mutex
13-
end
14-
15-
public :state=, :compare_and_set_state, :if_state, :mutex
10+
public :state=, :compare_and_set_state, :if_state
1611
attr_writer :value, :reason
1712
end
1813
end
@@ -278,7 +273,8 @@ def initialize
278273
end
279274

280275
it 'should execute the block within the mutex' do
281-
obligation.if_state(:unscheduled) { expect(obligation.mutex).to be_locked }
276+
expect(obligation).to receive(:synchronize)
277+
obligation.if_state(:unscheduled) { nil }
282278
end
283279
end
284280

0 commit comments

Comments
 (0)