o-concurrent-ruby 1.1.11
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 +7 -0
- data/CHANGELOG.md +542 -0
- data/Gemfile +37 -0
- data/LICENSE.txt +21 -0
- data/README.md +404 -0
- data/Rakefile +307 -0
- data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +189 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
- data/lib/concurrent-ruby/concurrent/agent.rb +587 -0
- data/lib/concurrent-ruby/concurrent/array.rb +66 -0
- data/lib/concurrent-ruby/concurrent/async.rb +449 -0
- data/lib/concurrent-ruby/concurrent/atom.rb +222 -0
- data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +66 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +126 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +143 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
- data/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb +100 -0
- data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +128 -0
- data/lib/concurrent-ruby/concurrent/atomic/event.rb +109 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +42 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +37 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +44 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +131 -0
- data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +254 -0
- data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +377 -0
- data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +181 -0
- data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +166 -0
- data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +104 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +56 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
- data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
- data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
- data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +111 -0
- data/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
- data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
- data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
- data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +66 -0
- data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
- data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +82 -0
- data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
- data/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
- data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +160 -0
- data/lib/concurrent-ruby/concurrent/concern/deprecation.rb +34 -0
- data/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb +73 -0
- data/lib/concurrent-ruby/concurrent/concern/logging.rb +32 -0
- data/lib/concurrent-ruby/concurrent/concern/obligation.rb +220 -0
- data/lib/concurrent-ruby/concurrent/concern/observable.rb +110 -0
- data/lib/concurrent-ruby/concurrent/configuration.rb +188 -0
- data/lib/concurrent-ruby/concurrent/constants.rb +8 -0
- data/lib/concurrent-ruby/concurrent/dataflow.rb +81 -0
- data/lib/concurrent-ruby/concurrent/delay.rb +199 -0
- data/lib/concurrent-ruby/concurrent/errors.rb +69 -0
- data/lib/concurrent-ruby/concurrent/exchanger.rb +352 -0
- data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +131 -0
- data/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb +62 -0
- data/lib/concurrent-ruby/concurrent/executor/executor_service.rb +185 -0
- data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +220 -0
- data/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb +66 -0
- data/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb +44 -0
- data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +103 -0
- data/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb +30 -0
- data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +140 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +82 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +21 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +368 -0
- data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +35 -0
- data/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb +34 -0
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +107 -0
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb +28 -0
- data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +100 -0
- data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +57 -0
- data/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb +88 -0
- data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +172 -0
- data/lib/concurrent-ruby/concurrent/executors.rb +20 -0
- data/lib/concurrent-ruby/concurrent/future.rb +141 -0
- data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
- data/lib/concurrent-ruby/concurrent/immutable_struct.rb +101 -0
- data/lib/concurrent-ruby/concurrent/ivar.rb +207 -0
- data/lib/concurrent-ruby/concurrent/map.rb +346 -0
- data/lib/concurrent-ruby/concurrent/maybe.rb +229 -0
- data/lib/concurrent-ruby/concurrent/mutable_struct.rb +239 -0
- data/lib/concurrent-ruby/concurrent/mvar.rb +242 -0
- data/lib/concurrent-ruby/concurrent/options.rb +42 -0
- data/lib/concurrent-ruby/concurrent/promise.rb +580 -0
- data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
- data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +331 -0
- data/lib/concurrent-ruby/concurrent/set.rb +74 -0
- data/lib/concurrent-ruby/concurrent/settable_struct.rb +139 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +98 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +24 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +171 -0
- data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +60 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +13 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +45 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +72 -0
- data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +44 -0
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
- data/lib/concurrent-ruby/concurrent/synchronization/object.rb +183 -0
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +71 -0
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +49 -0
- data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
- data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization.rb +30 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +50 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +74 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb +246 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb +75 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util.rb +16 -0
- data/lib/concurrent-ruby/concurrent/timer_task.rb +311 -0
- data/lib/concurrent-ruby/concurrent/tuple.rb +86 -0
- data/lib/concurrent-ruby/concurrent/tvar.rb +221 -0
- data/lib/concurrent-ruby/concurrent/utility/engine.rb +56 -0
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
- data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
- data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +53 -0
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +130 -0
- data/lib/concurrent-ruby/concurrent/version.rb +3 -0
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
- data/lib/concurrent-ruby/concurrent.rb +134 -0
- metadata +192 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'concurrent/utility/engine'
|
2
|
+
require 'concurrent/atomic/mutex_count_down_latch'
|
3
|
+
require 'concurrent/atomic/java_count_down_latch'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
###################################################################
|
8
|
+
|
9
|
+
# @!macro count_down_latch_method_initialize
|
10
|
+
#
|
11
|
+
# Create a new `CountDownLatch` with the initial `count`.
|
12
|
+
#
|
13
|
+
# @param [new] count the initial count
|
14
|
+
#
|
15
|
+
# @raise [ArgumentError] if `count` is not an integer or is less than zero
|
16
|
+
|
17
|
+
# @!macro count_down_latch_method_wait
|
18
|
+
#
|
19
|
+
# Block on the latch until the counter reaches zero or until `timeout` is reached.
|
20
|
+
#
|
21
|
+
# @param [Fixnum] timeout the number of seconds to wait for the counter or `nil`
|
22
|
+
# to block indefinitely
|
23
|
+
# @return [Boolean] `true` if the `count` reaches zero else false on `timeout`
|
24
|
+
|
25
|
+
# @!macro count_down_latch_method_count_down
|
26
|
+
#
|
27
|
+
# Signal the latch to decrement the counter. Will signal all blocked threads when
|
28
|
+
# the `count` reaches zero.
|
29
|
+
|
30
|
+
# @!macro count_down_latch_method_count
|
31
|
+
#
|
32
|
+
# The current value of the counter.
|
33
|
+
#
|
34
|
+
# @return [Fixnum] the current value of the counter
|
35
|
+
|
36
|
+
###################################################################
|
37
|
+
|
38
|
+
# @!macro count_down_latch_public_api
|
39
|
+
#
|
40
|
+
# @!method initialize(count = 1)
|
41
|
+
# @!macro count_down_latch_method_initialize
|
42
|
+
#
|
43
|
+
# @!method wait(timeout = nil)
|
44
|
+
# @!macro count_down_latch_method_wait
|
45
|
+
#
|
46
|
+
# @!method count_down
|
47
|
+
# @!macro count_down_latch_method_count_down
|
48
|
+
#
|
49
|
+
# @!method count
|
50
|
+
# @!macro count_down_latch_method_count
|
51
|
+
|
52
|
+
###################################################################
|
53
|
+
|
54
|
+
# @!visibility private
|
55
|
+
# @!macro internal_implementation_note
|
56
|
+
CountDownLatchImplementation = case
|
57
|
+
when Concurrent.on_jruby?
|
58
|
+
JavaCountDownLatch
|
59
|
+
else
|
60
|
+
MutexCountDownLatch
|
61
|
+
end
|
62
|
+
private_constant :CountDownLatchImplementation
|
63
|
+
|
64
|
+
# @!macro count_down_latch
|
65
|
+
#
|
66
|
+
# A synchronization object that allows one thread to wait on multiple other threads.
|
67
|
+
# The thread that will wait creates a `CountDownLatch` and sets the initial value
|
68
|
+
# (normally equal to the number of other threads). The initiating thread passes the
|
69
|
+
# latch to the other threads then waits for the other threads by calling the `#wait`
|
70
|
+
# method. Each of the other threads calls `#count_down` when done with its work.
|
71
|
+
# When the latch counter reaches zero the waiting thread is unblocked and continues
|
72
|
+
# with its work. A `CountDownLatch` can be used only once. Its value cannot be reset.
|
73
|
+
#
|
74
|
+
# @!macro count_down_latch_public_api
|
75
|
+
# @example Waiter and Decrementer
|
76
|
+
# latch = Concurrent::CountDownLatch.new(3)
|
77
|
+
#
|
78
|
+
# waiter = Thread.new do
|
79
|
+
# latch.wait()
|
80
|
+
# puts ("Waiter released")
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# decrementer = Thread.new do
|
84
|
+
# sleep(1)
|
85
|
+
# latch.count_down
|
86
|
+
# puts latch.count
|
87
|
+
#
|
88
|
+
# sleep(1)
|
89
|
+
# latch.count_down
|
90
|
+
# puts latch.count
|
91
|
+
#
|
92
|
+
# sleep(1)
|
93
|
+
# latch.count_down
|
94
|
+
# puts latch.count
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# [waiter, decrementer].each(&:join)
|
98
|
+
class CountDownLatch < CountDownLatchImplementation
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'concurrent/synchronization'
|
2
|
+
require 'concurrent/utility/native_integer'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# A synchronization aid that allows a set of threads to all wait for each
|
7
|
+
# other to reach a common barrier point.
|
8
|
+
# @example
|
9
|
+
# barrier = Concurrent::CyclicBarrier.new(3)
|
10
|
+
# jobs = Array.new(3) { |i| -> { sleep i; p done: i } }
|
11
|
+
# process = -> (i) do
|
12
|
+
# # waiting to start at the same time
|
13
|
+
# barrier.wait
|
14
|
+
# # execute job
|
15
|
+
# jobs[i].call
|
16
|
+
# # wait for others to finish
|
17
|
+
# barrier.wait
|
18
|
+
# end
|
19
|
+
# threads = 2.times.map do |i|
|
20
|
+
# Thread.new(i, &process)
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # use main as well
|
24
|
+
# process.call 2
|
25
|
+
#
|
26
|
+
# # here we can be sure that all jobs are processed
|
27
|
+
class CyclicBarrier < Synchronization::LockableObject
|
28
|
+
|
29
|
+
# @!visibility private
|
30
|
+
Generation = Struct.new(:status)
|
31
|
+
private_constant :Generation
|
32
|
+
|
33
|
+
# Create a new `CyclicBarrier` that waits for `parties` threads
|
34
|
+
#
|
35
|
+
# @param [Fixnum] parties the number of parties
|
36
|
+
# @yield an optional block that will be executed that will be executed after
|
37
|
+
# the last thread arrives and before the others are released
|
38
|
+
#
|
39
|
+
# @raise [ArgumentError] if `parties` is not an integer or is less than zero
|
40
|
+
def initialize(parties, &block)
|
41
|
+
Utility::NativeInteger.ensure_integer_and_bounds parties
|
42
|
+
Utility::NativeInteger.ensure_positive_and_no_zero parties
|
43
|
+
|
44
|
+
super(&nil)
|
45
|
+
synchronize { ns_initialize parties, &block }
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [Fixnum] the number of threads needed to pass the barrier
|
49
|
+
def parties
|
50
|
+
synchronize { @parties }
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [Fixnum] the number of threads currently waiting on the barrier
|
54
|
+
def number_waiting
|
55
|
+
synchronize { @number_waiting }
|
56
|
+
end
|
57
|
+
|
58
|
+
# Blocks on the barrier until the number of waiting threads is equal to
|
59
|
+
# `parties` or until `timeout` is reached or `reset` is called
|
60
|
+
# If a block has been passed to the constructor, it will be executed once by
|
61
|
+
# the last arrived thread before releasing the others
|
62
|
+
# @param [Fixnum] timeout the number of seconds to wait for the counter or
|
63
|
+
# `nil` to block indefinitely
|
64
|
+
# @return [Boolean] `true` if the `count` reaches zero else false on
|
65
|
+
# `timeout` or on `reset` or if the barrier is broken
|
66
|
+
def wait(timeout = nil)
|
67
|
+
synchronize do
|
68
|
+
|
69
|
+
return false unless @generation.status == :waiting
|
70
|
+
|
71
|
+
@number_waiting += 1
|
72
|
+
|
73
|
+
if @number_waiting == @parties
|
74
|
+
@action.call if @action
|
75
|
+
ns_generation_done @generation, :fulfilled
|
76
|
+
true
|
77
|
+
else
|
78
|
+
generation = @generation
|
79
|
+
if ns_wait_until(timeout) { generation.status != :waiting }
|
80
|
+
generation.status == :fulfilled
|
81
|
+
else
|
82
|
+
ns_generation_done generation, :broken, false
|
83
|
+
false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# resets the barrier to its initial state
|
90
|
+
# If there is at least one waiting thread, it will be woken up, the `wait`
|
91
|
+
# method will return false and the barrier will be broken
|
92
|
+
# If the barrier is broken, this method restores it to the original state
|
93
|
+
#
|
94
|
+
# @return [nil]
|
95
|
+
def reset
|
96
|
+
synchronize { ns_generation_done @generation, :reset }
|
97
|
+
end
|
98
|
+
|
99
|
+
# A barrier can be broken when:
|
100
|
+
# - a thread called the `reset` method while at least one other thread was waiting
|
101
|
+
# - at least one thread timed out on `wait` method
|
102
|
+
#
|
103
|
+
# A broken barrier can be restored using `reset` it's safer to create a new one
|
104
|
+
# @return [Boolean] true if the barrier is broken otherwise false
|
105
|
+
def broken?
|
106
|
+
synchronize { @generation.status != :waiting }
|
107
|
+
end
|
108
|
+
|
109
|
+
protected
|
110
|
+
|
111
|
+
def ns_generation_done(generation, status, continue = true)
|
112
|
+
generation.status = status
|
113
|
+
ns_next_generation if continue
|
114
|
+
ns_broadcast
|
115
|
+
end
|
116
|
+
|
117
|
+
def ns_next_generation
|
118
|
+
@generation = Generation.new(:waiting)
|
119
|
+
@number_waiting = 0
|
120
|
+
end
|
121
|
+
|
122
|
+
def ns_initialize(parties, &block)
|
123
|
+
@parties = parties
|
124
|
+
@action = block
|
125
|
+
ns_next_generation
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'concurrent/synchronization'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# Old school kernel-style event reminiscent of Win32 programming in C++.
|
7
|
+
#
|
8
|
+
# When an `Event` is created it is in the `unset` state. Threads can choose to
|
9
|
+
# `#wait` on the event, blocking until released by another thread. When one
|
10
|
+
# thread wants to alert all blocking threads it calls the `#set` method which
|
11
|
+
# will then wake up all listeners. Once an `Event` has been set it remains set.
|
12
|
+
# New threads calling `#wait` will return immediately. An `Event` may be
|
13
|
+
# `#reset` at any time once it has been set.
|
14
|
+
#
|
15
|
+
# @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682655.aspx
|
16
|
+
# @example
|
17
|
+
# event = Concurrent::Event.new
|
18
|
+
#
|
19
|
+
# t1 = Thread.new do
|
20
|
+
# puts "t1 is waiting"
|
21
|
+
# event.wait(1)
|
22
|
+
# puts "event occurred"
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# t2 = Thread.new do
|
26
|
+
# puts "t2 calling set"
|
27
|
+
# event.set
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# [t1, t2].each(&:join)
|
31
|
+
#
|
32
|
+
# # prints:
|
33
|
+
# # t1 is waiting
|
34
|
+
# # t2 calling set
|
35
|
+
# # event occurred
|
36
|
+
class Event < Synchronization::LockableObject
|
37
|
+
|
38
|
+
# Creates a new `Event` in the unset state. Threads calling `#wait` on the
|
39
|
+
# `Event` will block.
|
40
|
+
def initialize
|
41
|
+
super
|
42
|
+
synchronize { ns_initialize }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Is the object in the set state?
|
46
|
+
#
|
47
|
+
# @return [Boolean] indicating whether or not the `Event` has been set
|
48
|
+
def set?
|
49
|
+
synchronize { @set }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Trigger the event, setting the state to `set` and releasing all threads
|
53
|
+
# waiting on the event. Has no effect if the `Event` has already been set.
|
54
|
+
#
|
55
|
+
# @return [Boolean] should always return `true`
|
56
|
+
def set
|
57
|
+
synchronize { ns_set }
|
58
|
+
end
|
59
|
+
|
60
|
+
def try?
|
61
|
+
synchronize { @set ? false : ns_set }
|
62
|
+
end
|
63
|
+
|
64
|
+
# Reset a previously set event back to the `unset` state.
|
65
|
+
# Has no effect if the `Event` has not yet been set.
|
66
|
+
#
|
67
|
+
# @return [Boolean] should always return `true`
|
68
|
+
def reset
|
69
|
+
synchronize do
|
70
|
+
if @set
|
71
|
+
@set = false
|
72
|
+
@iteration +=1
|
73
|
+
end
|
74
|
+
true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Wait a given number of seconds for the `Event` to be set by another
|
79
|
+
# thread. Will wait forever when no `timeout` value is given. Returns
|
80
|
+
# immediately if the `Event` has already been set.
|
81
|
+
#
|
82
|
+
# @return [Boolean] true if the `Event` was set before timeout else false
|
83
|
+
def wait(timeout = nil)
|
84
|
+
synchronize do
|
85
|
+
unless @set
|
86
|
+
iteration = @iteration
|
87
|
+
ns_wait_until(timeout) { iteration < @iteration || @set }
|
88
|
+
else
|
89
|
+
true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
def ns_set
|
97
|
+
unless @set
|
98
|
+
@set = true
|
99
|
+
ns_broadcast
|
100
|
+
end
|
101
|
+
true
|
102
|
+
end
|
103
|
+
|
104
|
+
def ns_initialize
|
105
|
+
@set = false
|
106
|
+
@iteration = 0
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
if Concurrent.on_jruby?
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
# @!macro count_down_latch
|
6
|
+
# @!visibility private
|
7
|
+
# @!macro internal_implementation_note
|
8
|
+
class JavaCountDownLatch
|
9
|
+
|
10
|
+
# @!macro count_down_latch_method_initialize
|
11
|
+
def initialize(count = 1)
|
12
|
+
Utility::NativeInteger.ensure_integer_and_bounds(count)
|
13
|
+
Utility::NativeInteger.ensure_positive(count)
|
14
|
+
@latch = java.util.concurrent.CountDownLatch.new(count)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @!macro count_down_latch_method_wait
|
18
|
+
def wait(timeout = nil)
|
19
|
+
result = nil
|
20
|
+
if timeout.nil?
|
21
|
+
Synchronization::JRuby.sleep_interruptibly { @latch.await }
|
22
|
+
result = true
|
23
|
+
else
|
24
|
+
Synchronization::JRuby.sleep_interruptibly do
|
25
|
+
result = @latch.await(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
# @!macro count_down_latch_method_count_down
|
32
|
+
def count_down
|
33
|
+
@latch.countDown
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!macro count_down_latch_method_count
|
37
|
+
def count
|
38
|
+
@latch.getCount
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'concurrent/atomic/abstract_thread_local_var'
|
2
|
+
|
3
|
+
if Concurrent.on_jruby?
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# @!visibility private
|
8
|
+
# @!macro internal_implementation_note
|
9
|
+
class JavaThreadLocalVar < AbstractThreadLocalVar
|
10
|
+
|
11
|
+
# @!macro thread_local_var_method_get
|
12
|
+
def value
|
13
|
+
value = @var.get
|
14
|
+
|
15
|
+
if value.nil?
|
16
|
+
default
|
17
|
+
elsif value == NULL
|
18
|
+
nil
|
19
|
+
else
|
20
|
+
value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @!macro thread_local_var_method_set
|
25
|
+
def value=(value)
|
26
|
+
@var.set(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
# @!visibility private
|
32
|
+
def allocate_storage
|
33
|
+
@var = java.lang.ThreadLocal.new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'concurrent/synchronization'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
# @!macro atomic_boolean
|
6
|
+
# @!visibility private
|
7
|
+
# @!macro internal_implementation_note
|
8
|
+
class MutexAtomicBoolean < Synchronization::LockableObject
|
9
|
+
|
10
|
+
# @!macro atomic_boolean_method_initialize
|
11
|
+
def initialize(initial = false)
|
12
|
+
super()
|
13
|
+
synchronize { ns_initialize(initial) }
|
14
|
+
end
|
15
|
+
|
16
|
+
# @!macro atomic_boolean_method_value_get
|
17
|
+
def value
|
18
|
+
synchronize { @value }
|
19
|
+
end
|
20
|
+
|
21
|
+
# @!macro atomic_boolean_method_value_set
|
22
|
+
def value=(value)
|
23
|
+
synchronize { @value = !!value }
|
24
|
+
end
|
25
|
+
|
26
|
+
# @!macro atomic_boolean_method_true_question
|
27
|
+
def true?
|
28
|
+
synchronize { @value }
|
29
|
+
end
|
30
|
+
|
31
|
+
# @!macro atomic_boolean_method_false_question
|
32
|
+
def false?
|
33
|
+
synchronize { !@value }
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!macro atomic_boolean_method_make_true
|
37
|
+
def make_true
|
38
|
+
synchronize { ns_make_value(true) }
|
39
|
+
end
|
40
|
+
|
41
|
+
# @!macro atomic_boolean_method_make_false
|
42
|
+
def make_false
|
43
|
+
synchronize { ns_make_value(false) }
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
# @!visibility private
|
49
|
+
def ns_initialize(initial)
|
50
|
+
@value = !!initial
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# @!visibility private
|
56
|
+
def ns_make_value(value)
|
57
|
+
old = @value
|
58
|
+
@value = value
|
59
|
+
old != @value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'concurrent/synchronization'
|
2
|
+
require 'concurrent/utility/native_integer'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# @!macro atomic_fixnum
|
7
|
+
# @!visibility private
|
8
|
+
# @!macro internal_implementation_note
|
9
|
+
class MutexAtomicFixnum < Synchronization::LockableObject
|
10
|
+
|
11
|
+
# @!macro atomic_fixnum_method_initialize
|
12
|
+
def initialize(initial = 0)
|
13
|
+
super()
|
14
|
+
synchronize { ns_initialize(initial) }
|
15
|
+
end
|
16
|
+
|
17
|
+
# @!macro atomic_fixnum_method_value_get
|
18
|
+
def value
|
19
|
+
synchronize { @value }
|
20
|
+
end
|
21
|
+
|
22
|
+
# @!macro atomic_fixnum_method_value_set
|
23
|
+
def value=(value)
|
24
|
+
synchronize { ns_set(value) }
|
25
|
+
end
|
26
|
+
|
27
|
+
# @!macro atomic_fixnum_method_increment
|
28
|
+
def increment(delta = 1)
|
29
|
+
synchronize { ns_set(@value + delta.to_i) }
|
30
|
+
end
|
31
|
+
|
32
|
+
alias_method :up, :increment
|
33
|
+
|
34
|
+
# @!macro atomic_fixnum_method_decrement
|
35
|
+
def decrement(delta = 1)
|
36
|
+
synchronize { ns_set(@value - delta.to_i) }
|
37
|
+
end
|
38
|
+
|
39
|
+
alias_method :down, :decrement
|
40
|
+
|
41
|
+
# @!macro atomic_fixnum_method_compare_and_set
|
42
|
+
def compare_and_set(expect, update)
|
43
|
+
synchronize do
|
44
|
+
if @value == expect.to_i
|
45
|
+
@value = update.to_i
|
46
|
+
true
|
47
|
+
else
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @!macro atomic_fixnum_method_update
|
54
|
+
def update
|
55
|
+
synchronize do
|
56
|
+
@value = yield @value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
# @!visibility private
|
63
|
+
def ns_initialize(initial)
|
64
|
+
ns_set(initial)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# @!visibility private
|
70
|
+
def ns_set(value)
|
71
|
+
Utility::NativeInteger.ensure_integer_and_bounds value
|
72
|
+
@value = value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'concurrent/synchronization'
|
2
|
+
require 'concurrent/utility/native_integer'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# @!macro count_down_latch
|
7
|
+
# @!visibility private
|
8
|
+
# @!macro internal_implementation_note
|
9
|
+
class MutexCountDownLatch < Synchronization::LockableObject
|
10
|
+
|
11
|
+
# @!macro count_down_latch_method_initialize
|
12
|
+
def initialize(count = 1)
|
13
|
+
Utility::NativeInteger.ensure_integer_and_bounds count
|
14
|
+
Utility::NativeInteger.ensure_positive count
|
15
|
+
|
16
|
+
super()
|
17
|
+
synchronize { ns_initialize count }
|
18
|
+
end
|
19
|
+
|
20
|
+
# @!macro count_down_latch_method_wait
|
21
|
+
def wait(timeout = nil)
|
22
|
+
synchronize { ns_wait_until(timeout) { @count == 0 } }
|
23
|
+
end
|
24
|
+
|
25
|
+
# @!macro count_down_latch_method_count_down
|
26
|
+
def count_down
|
27
|
+
synchronize do
|
28
|
+
@count -= 1 if @count > 0
|
29
|
+
ns_broadcast if @count == 0
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @!macro count_down_latch_method_count
|
34
|
+
def count
|
35
|
+
synchronize { @count }
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def ns_initialize(count)
|
41
|
+
@count = count
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|