concurrent-ruby 0.8.0 → 0.9.0.pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +97 -2
- data/README.md +103 -54
- data/lib/concurrent.rb +34 -14
- data/lib/concurrent/async.rb +164 -50
- data/lib/concurrent/atom.rb +171 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
- data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
- data/lib/concurrent/atomic/atomic_reference.rb +49 -0
- data/lib/concurrent/atomic/condition.rb +23 -12
- data/lib/concurrent/atomic/count_down_latch.rb +23 -21
- data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
- data/lib/concurrent/atomic/event.rb +33 -42
- data/lib/concurrent/atomic/read_write_lock.rb +252 -0
- data/lib/concurrent/atomic/semaphore.rb +64 -89
- data/lib/concurrent/atomic/thread_local_var.rb +130 -58
- data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +3 -0
- data/lib/concurrent/atomic_reference/jruby.rb +6 -3
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +10 -32
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
- data/lib/concurrent/atomic_reference/rbx.rb +4 -1
- data/lib/concurrent/atomic_reference/ruby.rb +6 -3
- data/lib/concurrent/atomics.rb +74 -4
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
- data/lib/concurrent/collection/priority_queue.rb +300 -245
- data/lib/concurrent/concern/deprecation.rb +27 -0
- data/lib/concurrent/concern/dereferenceable.rb +88 -0
- data/lib/concurrent/concern/logging.rb +25 -0
- data/lib/concurrent/concern/obligation.rb +228 -0
- data/lib/concurrent/concern/observable.rb +85 -0
- data/lib/concurrent/configuration.rb +226 -112
- data/lib/concurrent/dataflow.rb +2 -3
- data/lib/concurrent/delay.rb +141 -50
- data/lib/concurrent/edge.rb +30 -0
- data/lib/concurrent/errors.rb +10 -0
- data/lib/concurrent/exchanger.rb +25 -1
- data/lib/concurrent/executor/cached_thread_pool.rb +46 -33
- data/lib/concurrent/executor/executor.rb +46 -299
- data/lib/concurrent/executor/executor_service.rb +521 -0
- data/lib/concurrent/executor/fixed_thread_pool.rb +206 -26
- data/lib/concurrent/executor/immediate_executor.rb +9 -9
- data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
- data/lib/concurrent/executor/java_cached_thread_pool.rb +18 -16
- data/lib/concurrent/executor/java_fixed_thread_pool.rb +11 -18
- data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
- data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +9 -18
- data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +10 -21
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
- data/lib/concurrent/executor/safe_task_executor.rb +5 -4
- data/lib/concurrent/executor/serialized_execution.rb +22 -18
- data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
- data/lib/concurrent/executor/single_thread_executor.rb +32 -21
- data/lib/concurrent/executor/thread_pool_executor.rb +72 -60
- data/lib/concurrent/executor/timer_set.rb +96 -84
- data/lib/concurrent/executors.rb +1 -1
- data/lib/concurrent/future.rb +70 -38
- data/lib/concurrent/immutable_struct.rb +89 -0
- data/lib/concurrent/ivar.rb +152 -60
- data/lib/concurrent/lazy_register.rb +40 -20
- data/lib/concurrent/maybe.rb +226 -0
- data/lib/concurrent/mutable_struct.rb +227 -0
- data/lib/concurrent/mvar.rb +44 -43
- data/lib/concurrent/promise.rb +208 -134
- data/lib/concurrent/scheduled_task.rb +339 -43
- data/lib/concurrent/settable_struct.rb +127 -0
- data/lib/concurrent/synchronization.rb +17 -0
- data/lib/concurrent/synchronization/abstract_object.rb +163 -0
- data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
- data/lib/concurrent/synchronization/condition.rb +53 -0
- data/lib/concurrent/synchronization/java_object.rb +35 -0
- data/lib/concurrent/synchronization/lock.rb +32 -0
- data/lib/concurrent/synchronization/monitor_object.rb +24 -0
- data/lib/concurrent/synchronization/mutex_object.rb +43 -0
- data/lib/concurrent/synchronization/object.rb +78 -0
- data/lib/concurrent/synchronization/rbx_object.rb +75 -0
- data/lib/concurrent/timer_task.rb +87 -100
- data/lib/concurrent/tvar.rb +42 -38
- data/lib/concurrent/utilities.rb +3 -1
- data/lib/concurrent/utility/at_exit.rb +97 -0
- data/lib/concurrent/utility/engine.rb +40 -0
- data/lib/concurrent/utility/monotonic_time.rb +59 -0
- data/lib/concurrent/utility/native_extension_loader.rb +56 -0
- data/lib/concurrent/utility/processor_counter.rb +156 -0
- data/lib/concurrent/utility/timeout.rb +18 -14
- data/lib/concurrent/utility/timer.rb +11 -6
- data/lib/concurrent/version.rb +2 -1
- data/lib/concurrent_ruby.rb +1 -0
- metadata +47 -83
- data/lib/concurrent/actor.rb +0 -103
- data/lib/concurrent/actor/behaviour.rb +0 -70
- data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
- data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
- data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
- data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
- data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
- data/lib/concurrent/actor/behaviour/linking.rb +0 -45
- data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
- data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
- data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
- data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
- data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
- data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
- data/lib/concurrent/actor/behaviour/termination.rb +0 -54
- data/lib/concurrent/actor/context.rb +0 -154
- data/lib/concurrent/actor/core.rb +0 -217
- data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
- data/lib/concurrent/actor/envelope.rb +0 -41
- data/lib/concurrent/actor/errors.rb +0 -27
- data/lib/concurrent/actor/internal_delegations.rb +0 -49
- data/lib/concurrent/actor/public_delegations.rb +0 -40
- data/lib/concurrent/actor/reference.rb +0 -81
- data/lib/concurrent/actor/root.rb +0 -37
- data/lib/concurrent/actor/type_check.rb +0 -48
- data/lib/concurrent/actor/utils.rb +0 -10
- data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
- data/lib/concurrent/actor/utils/balancer.rb +0 -42
- data/lib/concurrent/actor/utils/broadcast.rb +0 -52
- data/lib/concurrent/actor/utils/pool.rb +0 -59
- data/lib/concurrent/actress.rb +0 -3
- data/lib/concurrent/agent.rb +0 -209
- data/lib/concurrent/atomic.rb +0 -92
- data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
- data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
- data/lib/concurrent/atomic/synchronization.rb +0 -51
- data/lib/concurrent/channel/buffered_channel.rb +0 -85
- data/lib/concurrent/channel/channel.rb +0 -41
- data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
- data/lib/concurrent/channel/waitable_list.rb +0 -40
- data/lib/concurrent/channels.rb +0 -5
- data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
- data/lib/concurrent/collection/ring_buffer.rb +0 -59
- data/lib/concurrent/collections.rb +0 -3
- data/lib/concurrent/dereferenceable.rb +0 -108
- data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
- data/lib/concurrent/logging.rb +0 -20
- data/lib/concurrent/obligation.rb +0 -171
- data/lib/concurrent/observable.rb +0 -73
- data/lib/concurrent/options_parser.rb +0 -52
- data/lib/concurrent/utility/processor_count.rb +0 -152
- data/lib/extension_helper.rb +0 -37
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'concurrent/utility/native_extension_loader'
|
2
|
+
require 'concurrent/utility/engine'
|
3
|
+
require 'concurrent/atomic_reference/concurrent_update_error'
|
4
|
+
require 'concurrent/atomic_reference/mutex_atomic'
|
5
|
+
|
6
|
+
begin
|
7
|
+
# force fallback impl with FORCE_ATOMIC_FALLBACK=1
|
8
|
+
if /[^0fF]/ =~ ENV['FORCE_ATOMIC_FALLBACK']
|
9
|
+
ruby_engine = 'mutex_atomic'
|
10
|
+
else
|
11
|
+
ruby_engine = Concurrent.ruby_engine
|
12
|
+
end
|
13
|
+
|
14
|
+
require "concurrent/atomic_reference/#{ruby_engine}"
|
15
|
+
rescue LoadError
|
16
|
+
#warn 'Compiled extensions not installed, pure Ruby Atomic will be used.'
|
17
|
+
end
|
18
|
+
|
19
|
+
if defined? Concurrent::JavaAtomicReference
|
20
|
+
|
21
|
+
# @!macro atomic_reference
|
22
|
+
class Concurrent::AtomicReference < Concurrent::JavaAtomicReference
|
23
|
+
end
|
24
|
+
|
25
|
+
elsif defined? Concurrent::RbxAtomicReference
|
26
|
+
|
27
|
+
# @!macro atomic_reference
|
28
|
+
class Concurrent::AtomicReference < Concurrent::RbxAtomicReference
|
29
|
+
end
|
30
|
+
|
31
|
+
elsif defined? Concurrent::CAtomicReference
|
32
|
+
|
33
|
+
# @!macro atomic_reference
|
34
|
+
class Concurrent::AtomicReference < Concurrent::CAtomicReference
|
35
|
+
end
|
36
|
+
|
37
|
+
else
|
38
|
+
|
39
|
+
# @!macro atomic_reference
|
40
|
+
class Concurrent::AtomicReference < Concurrent::MutexAtomicReference
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Concurrent
|
45
|
+
|
46
|
+
# @see Concurrent::AtomicReference
|
47
|
+
# @deprecated Use Concurrent::AtomicReference instead.
|
48
|
+
Atomic = AtomicReference
|
49
|
+
end
|
@@ -1,14 +1,21 @@
|
|
1
|
+
require 'concurrent/utility/monotonic_time'
|
2
|
+
require 'concurrent/concern/deprecation'
|
3
|
+
|
1
4
|
module Concurrent
|
2
5
|
|
3
|
-
# Condition is a better implementation of standard Ruby ConditionVariable.
|
4
|
-
#
|
5
|
-
# Condition::Result which make possible to know if waiting thread has been
|
6
|
-
# by an another thread (using #signal or #broadcast) or due to
|
6
|
+
# Condition is a better implementation of standard Ruby ConditionVariable. The
|
7
|
+
# biggest difference is the wait return value: Condition#wait returns
|
8
|
+
# Condition::Result which make possible to know if waiting thread has been
|
9
|
+
# woken up by an another thread (using #signal or #broadcast) or due to
|
10
|
+
# timeout.
|
11
|
+
#
|
12
|
+
# Every #wait must be guarded by a locked Mutex or a ThreadError will be
|
13
|
+
# risen. Although it's not mandatory, it's recommended to call also #signal
|
14
|
+
# and #broadcast within the same mutex
|
7
15
|
#
|
8
|
-
#
|
9
|
-
# Although it's not mandatory, it's recommended to call also #signal and #broadcast within
|
10
|
-
# the same mutex
|
16
|
+
# @deprecated
|
11
17
|
class Condition
|
18
|
+
include Concern::Deprecation
|
12
19
|
|
13
20
|
class Result
|
14
21
|
def initialize(remaining_time)
|
@@ -17,12 +24,14 @@ module Concurrent
|
|
17
24
|
|
18
25
|
attr_reader :remaining_time
|
19
26
|
|
20
|
-
# @return [Boolean] true if current thread has been waken up by a #signal
|
27
|
+
# @return [Boolean] true if current thread has been waken up by a #signal
|
28
|
+
# or a #broadcast call , otherwise false
|
21
29
|
def woken_up?
|
22
30
|
@remaining_time.nil? || @remaining_time > 0
|
23
31
|
end
|
24
32
|
|
25
|
-
# @return [Boolean] true if current thread has been waken up due to a
|
33
|
+
# @return [Boolean] true if current thread has been waken up due to a
|
34
|
+
# timeout, otherwise false
|
26
35
|
def timed_out?
|
27
36
|
@remaining_time != nil && @remaining_time <= 0
|
28
37
|
end
|
@@ -32,20 +41,23 @@ module Concurrent
|
|
32
41
|
end
|
33
42
|
|
34
43
|
def initialize
|
44
|
+
deprecated 'Will be replaced with Synchronization::Object in v1.0.'
|
35
45
|
@condition = ConditionVariable.new
|
36
46
|
end
|
37
47
|
|
38
48
|
# @param [Mutex] mutex the locked mutex guarding the wait
|
39
49
|
# @param [Object] timeout nil means no timeout
|
40
50
|
# @return [Result]
|
51
|
+
#
|
52
|
+
# @!macro monotonic_clock_warning
|
41
53
|
def wait(mutex, timeout = nil)
|
42
|
-
start_time =
|
54
|
+
start_time = Concurrent.monotonic_time
|
43
55
|
@condition.wait(mutex, timeout)
|
44
56
|
|
45
57
|
if timeout.nil?
|
46
58
|
Result.new(nil)
|
47
59
|
else
|
48
|
-
Result.new(start_time + timeout -
|
60
|
+
Result.new(start_time + timeout - Concurrent.monotonic_time)
|
49
61
|
end
|
50
62
|
end
|
51
63
|
|
@@ -62,6 +74,5 @@ module Concurrent
|
|
62
74
|
@condition.broadcast
|
63
75
|
true
|
64
76
|
end
|
65
|
-
|
66
77
|
end
|
67
78
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'concurrent/
|
1
|
+
require 'concurrent/synchronization'
|
2
2
|
|
3
3
|
module Concurrent
|
4
4
|
|
@@ -11,7 +11,10 @@ module Concurrent
|
|
11
11
|
# method. Each of the other threads calls `#count_down` when done with its work.
|
12
12
|
# When the latch counter reaches zero the waiting thread is unblocked and continues
|
13
13
|
# with its work. A `CountDownLatch` can be used only once. Its value cannot be reset.
|
14
|
-
|
14
|
+
#
|
15
|
+
# @!visibility private
|
16
|
+
# @!macro internal_implementation_note
|
17
|
+
class PureCountDownLatch < Synchronization::Object
|
15
18
|
|
16
19
|
# @!macro [attach] count_down_latch_method_initialize
|
17
20
|
#
|
@@ -20,13 +23,12 @@ module Concurrent
|
|
20
23
|
# @param [Fixnum] count the initial count
|
21
24
|
#
|
22
25
|
# @raise [ArgumentError] if `count` is not an integer or is less than zero
|
23
|
-
def initialize(count)
|
26
|
+
def initialize(count = 1)
|
24
27
|
unless count.is_a?(Fixnum) && count >= 0
|
25
28
|
raise ArgumentError.new('count must be in integer greater than or equal zero')
|
26
29
|
end
|
27
|
-
|
28
|
-
|
29
|
-
@count = count
|
30
|
+
super()
|
31
|
+
synchronize { ns_initialize count }
|
30
32
|
end
|
31
33
|
|
32
34
|
# @!macro [attach] count_down_latch_method_wait
|
@@ -37,15 +39,7 @@ module Concurrent
|
|
37
39
|
# to block indefinitely
|
38
40
|
# @return [Boolean] `true` if the `count` reaches zero else false on `timeout`
|
39
41
|
def wait(timeout = nil)
|
40
|
-
|
41
|
-
|
42
|
-
remaining = Condition::Result.new(timeout)
|
43
|
-
while @count > 0 && remaining.can_wait?
|
44
|
-
remaining = @condition.wait(@mutex, remaining.remaining_time)
|
45
|
-
end
|
46
|
-
|
47
|
-
@count == 0
|
48
|
-
end
|
42
|
+
synchronize { ns_wait_until(timeout) { @count == 0 } }
|
49
43
|
end
|
50
44
|
|
51
45
|
# @!macro [attach] count_down_latch_method_count_down
|
@@ -53,9 +47,9 @@ module Concurrent
|
|
53
47
|
# Signal the latch to decrement the counter. Will signal all blocked threads when
|
54
48
|
# the `count` reaches zero.
|
55
49
|
def count_down
|
56
|
-
|
50
|
+
synchronize do
|
57
51
|
@count -= 1 if @count > 0
|
58
|
-
|
52
|
+
ns_broadcast if @count == 0
|
59
53
|
end
|
60
54
|
end
|
61
55
|
|
@@ -65,17 +59,25 @@ module Concurrent
|
|
65
59
|
#
|
66
60
|
# @return [Fixnum] the current value of the counter
|
67
61
|
def count
|
68
|
-
|
62
|
+
synchronize { @count }
|
63
|
+
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
def ns_initialize(count)
|
68
|
+
@count = count
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
if
|
72
|
+
if Concurrent.on_jruby?
|
73
73
|
|
74
74
|
# @!macro count_down_latch
|
75
|
+
# @!visibility private
|
76
|
+
# @!macro internal_implementation_note
|
75
77
|
class JavaCountDownLatch
|
76
78
|
|
77
79
|
# @!macro count_down_latch_method_initialize
|
78
|
-
def initialize(count)
|
80
|
+
def initialize(count = 1)
|
79
81
|
unless count.is_a?(Fixnum) && count >= 0
|
80
82
|
raise ArgumentError.new('count must be in integer greater than or equal zero')
|
81
83
|
end
|
@@ -110,7 +112,7 @@ module Concurrent
|
|
110
112
|
else
|
111
113
|
|
112
114
|
# @!macro count_down_latch
|
113
|
-
class CountDownLatch <
|
115
|
+
class CountDownLatch < PureCountDownLatch
|
114
116
|
end
|
115
117
|
end
|
116
118
|
end
|
@@ -1,42 +1,48 @@
|
|
1
|
+
require 'concurrent/synchronization'
|
2
|
+
|
1
3
|
module Concurrent
|
2
4
|
|
3
|
-
class CyclicBarrier
|
5
|
+
class CyclicBarrier < Synchronization::Object
|
4
6
|
|
7
|
+
# @!visibility private
|
5
8
|
Generation = Struct.new(:status)
|
6
9
|
private_constant :Generation
|
7
10
|
|
8
11
|
# Create a new `CyclicBarrier` that waits for `parties` threads
|
9
12
|
#
|
10
13
|
# @param [Fixnum] parties the number of parties
|
11
|
-
# @yield an optional block that will be executed that will be executed after
|
14
|
+
# @yield an optional block that will be executed that will be executed after
|
15
|
+
# the last thread arrives and before the others are released
|
12
16
|
#
|
13
17
|
# @raise [ArgumentError] if `parties` is not an integer or is less than zero
|
14
18
|
def initialize(parties, &block)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@action = block
|
21
|
-
@generation = Generation.new(:waiting)
|
19
|
+
if !parties.is_a?(Fixnum) || parties < 1
|
20
|
+
raise ArgumentError.new('count must be in integer greater than or equal zero')
|
21
|
+
end
|
22
|
+
super(&nil)
|
23
|
+
synchronize { ns_initialize parties, &block }
|
22
24
|
end
|
23
25
|
|
24
26
|
# @return [Fixnum] the number of threads needed to pass the barrier
|
25
27
|
def parties
|
26
|
-
@parties
|
28
|
+
synchronize { @parties }
|
27
29
|
end
|
28
30
|
|
29
31
|
# @return [Fixnum] the number of threads currently waiting on the barrier
|
30
32
|
def number_waiting
|
31
|
-
@number_waiting
|
33
|
+
synchronize { @number_waiting }
|
32
34
|
end
|
33
35
|
|
34
|
-
# Blocks on the barrier until the number of waiting threads is equal to
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
36
|
+
# Blocks on the barrier until the number of waiting threads is equal to
|
37
|
+
# `parties` or until `timeout` is reached or `reset` is called
|
38
|
+
# If a block has been passed to the constructor, it will be executed once by
|
39
|
+
# the last arrived thread before releasing the others
|
40
|
+
# @param [Fixnum] timeout the number of seconds to wait for the counter or
|
41
|
+
# `nil` to block indefinitely
|
42
|
+
# @return [Boolean] `true` if the `count` reaches zero else false on
|
43
|
+
# `timeout` or on `reset` or if the barrier is broken
|
38
44
|
def wait(timeout = nil)
|
39
|
-
|
45
|
+
synchronize do
|
40
46
|
|
41
47
|
return false unless @generation.status == :waiting
|
42
48
|
|
@@ -44,25 +50,28 @@ module Concurrent
|
|
44
50
|
|
45
51
|
if @number_waiting == @parties
|
46
52
|
@action.call if @action
|
47
|
-
|
53
|
+
ns_generation_done @generation, :fulfilled
|
48
54
|
true
|
49
55
|
else
|
50
|
-
|
56
|
+
generation = @generation
|
57
|
+
if ns_wait_until(timeout) { generation.status != :waiting }
|
58
|
+
generation.status == :fulfilled
|
59
|
+
else
|
60
|
+
ns_generation_done generation, :broken, false
|
61
|
+
false
|
62
|
+
end
|
51
63
|
end
|
52
64
|
end
|
53
65
|
end
|
54
66
|
|
55
|
-
|
56
|
-
|
57
67
|
# resets the barrier to its initial state
|
58
|
-
# If there is at least one waiting thread, it will be woken up, the `wait`
|
68
|
+
# If there is at least one waiting thread, it will be woken up, the `wait`
|
69
|
+
# method will return false and the barrier will be broken
|
59
70
|
# If the barrier is broken, this method restores it to the original state
|
60
71
|
#
|
61
72
|
# @return [nil]
|
62
73
|
def reset
|
63
|
-
|
64
|
-
set_status_and_restore(:reset)
|
65
|
-
end
|
74
|
+
synchronize { ns_generation_done @generation, :reset }
|
66
75
|
end
|
67
76
|
|
68
77
|
# A barrier can be broken when:
|
@@ -72,35 +81,26 @@ module Concurrent
|
|
72
81
|
# A broken barrier can be restored using `reset` it's safer to create a new one
|
73
82
|
# @return [Boolean] true if the barrier is broken otherwise false
|
74
83
|
def broken?
|
75
|
-
|
84
|
+
synchronize { @generation.status != :waiting }
|
76
85
|
end
|
77
86
|
|
78
|
-
|
87
|
+
protected
|
79
88
|
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
@number_waiting = 0
|
89
|
+
def ns_generation_done(generation, status, continue = true)
|
90
|
+
generation.status = status
|
91
|
+
ns_next_generation if continue
|
92
|
+
ns_broadcast
|
85
93
|
end
|
86
94
|
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
else
|
91
|
-
generation.status = :broken
|
92
|
-
@condition.broadcast
|
93
|
-
false
|
94
|
-
end
|
95
|
+
def ns_next_generation
|
96
|
+
@generation = Generation.new(:waiting)
|
97
|
+
@number_waiting = 0
|
95
98
|
end
|
96
99
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end
|
102
|
-
remaining.woken_up?
|
100
|
+
def ns_initialize(parties, &block)
|
101
|
+
@parties = parties
|
102
|
+
@action = block
|
103
|
+
ns_next_generation
|
103
104
|
end
|
104
|
-
|
105
105
|
end
|
106
|
-
end
|
106
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'thread'
|
2
|
-
require 'concurrent/
|
2
|
+
require 'concurrent/synchronization'
|
3
3
|
|
4
4
|
module Concurrent
|
5
5
|
|
@@ -13,24 +13,20 @@ module Concurrent
|
|
13
13
|
# `#reset` at any time once it has been set.
|
14
14
|
#
|
15
15
|
# @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682655.aspx
|
16
|
-
class Event
|
16
|
+
class Event < Synchronization::Object
|
17
17
|
|
18
18
|
# Creates a new `Event` in the unset state. Threads calling `#wait` on the
|
19
19
|
# `Event` will block.
|
20
20
|
def initialize
|
21
|
-
|
22
|
-
|
23
|
-
@condition = Condition.new
|
21
|
+
super
|
22
|
+
synchronize { ns_initialize }
|
24
23
|
end
|
25
24
|
|
26
25
|
# Is the object in the set state?
|
27
26
|
#
|
28
27
|
# @return [Boolean] indicating whether or not the `Event` has been set
|
29
28
|
def set?
|
30
|
-
@
|
31
|
-
@set
|
32
|
-
ensure
|
33
|
-
@mutex.unlock
|
29
|
+
synchronize { @set }
|
34
30
|
end
|
35
31
|
|
36
32
|
# Trigger the event, setting the state to `set` and releasing all threads
|
@@ -38,29 +34,11 @@ module Concurrent
|
|
38
34
|
#
|
39
35
|
# @return [Boolean] should always return `true`
|
40
36
|
def set
|
41
|
-
|
42
|
-
unless @set
|
43
|
-
@set = true
|
44
|
-
@condition.broadcast
|
45
|
-
end
|
46
|
-
true
|
47
|
-
ensure
|
48
|
-
@mutex.unlock
|
37
|
+
synchronize { ns_set }
|
49
38
|
end
|
50
39
|
|
51
40
|
def try?
|
52
|
-
@
|
53
|
-
|
54
|
-
if @set
|
55
|
-
false
|
56
|
-
else
|
57
|
-
@set = true
|
58
|
-
@condition.broadcast
|
59
|
-
true
|
60
|
-
end
|
61
|
-
|
62
|
-
ensure
|
63
|
-
@mutex.unlock
|
41
|
+
synchronize { @set ? false : ns_set }
|
64
42
|
end
|
65
43
|
|
66
44
|
# Reset a previously set event back to the `unset` state.
|
@@ -68,11 +46,13 @@ module Concurrent
|
|
68
46
|
#
|
69
47
|
# @return [Boolean] should always return `true`
|
70
48
|
def reset
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
49
|
+
synchronize do
|
50
|
+
if @set
|
51
|
+
@set = false
|
52
|
+
@iteration +=1
|
53
|
+
end
|
54
|
+
true
|
55
|
+
end
|
76
56
|
end
|
77
57
|
|
78
58
|
# Wait a given number of seconds for the `Event` to be set by another
|
@@ -81,18 +61,29 @@ module Concurrent
|
|
81
61
|
#
|
82
62
|
# @return [Boolean] true if the `Event` was set before timeout else false
|
83
63
|
def wait(timeout = nil)
|
84
|
-
|
64
|
+
synchronize do
|
65
|
+
unless @set
|
66
|
+
iteration = @iteration
|
67
|
+
ns_wait_until(timeout) { iteration < @iteration || @set }
|
68
|
+
else
|
69
|
+
true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
85
73
|
|
74
|
+
protected
|
75
|
+
|
76
|
+
def ns_set
|
86
77
|
unless @set
|
87
|
-
|
88
|
-
|
89
|
-
remaining = @condition.wait(@mutex, remaining.remaining_time)
|
90
|
-
end
|
78
|
+
@set = true
|
79
|
+
ns_broadcast
|
91
80
|
end
|
81
|
+
true
|
82
|
+
end
|
92
83
|
|
93
|
-
|
94
|
-
|
95
|
-
@
|
84
|
+
def ns_initialize
|
85
|
+
@set = false
|
86
|
+
@iteration = 0
|
96
87
|
end
|
97
88
|
end
|
98
89
|
end
|