concurrent-ruby 0.6.0.pre.1 → 0.6.0.pre.2
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/README.md +16 -0
- data/lib/concurrent.rb +9 -29
- data/lib/concurrent/{actor.rb → actor/actor.rb} +3 -3
- data/lib/concurrent/actor/actor_context.rb +77 -0
- data/lib/concurrent/actor/actor_ref.rb +67 -0
- data/lib/concurrent/{postable.rb → actor/postable.rb} +1 -1
- data/lib/concurrent/actor/simple_actor_ref.rb +94 -0
- data/lib/concurrent/actors.rb +5 -0
- data/lib/concurrent/agent.rb +81 -47
- data/lib/concurrent/async.rb +35 -35
- data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +170 -0
- data/lib/concurrent/{condition.rb → atomic/condition.rb} +0 -0
- data/lib/concurrent/{copy_on_notify_observer_set.rb → atomic/copy_on_notify_observer_set.rb} +48 -13
- data/lib/concurrent/{copy_on_write_observer_set.rb → atomic/copy_on_write_observer_set.rb} +41 -20
- data/lib/concurrent/atomic/count_down_latch.rb +116 -0
- data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
- data/lib/concurrent/atomic/event.rb +103 -0
- data/lib/concurrent/{thread_local_var.rb → atomic/thread_local_var.rb} +0 -0
- data/lib/concurrent/atomics.rb +9 -0
- data/lib/concurrent/channel/buffered_channel.rb +6 -4
- data/lib/concurrent/channel/channel.rb +30 -2
- data/lib/concurrent/channel/unbuffered_channel.rb +2 -2
- data/lib/concurrent/channel/waitable_list.rb +3 -1
- data/lib/concurrent/channels.rb +5 -0
- data/lib/concurrent/{channel → collection}/blocking_ring_buffer.rb +16 -5
- data/lib/concurrent/collection/priority_queue.rb +305 -0
- data/lib/concurrent/{channel → collection}/ring_buffer.rb +6 -1
- data/lib/concurrent/collections.rb +3 -0
- data/lib/concurrent/configuration.rb +68 -19
- data/lib/concurrent/dataflow.rb +9 -9
- data/lib/concurrent/delay.rb +21 -13
- data/lib/concurrent/dereferenceable.rb +40 -33
- data/lib/concurrent/exchanger.rb +3 -0
- data/lib/concurrent/{cached_thread_pool.rb → executor/cached_thread_pool.rb} +8 -9
- data/lib/concurrent/executor/executor.rb +222 -0
- data/lib/concurrent/{fixed_thread_pool.rb → executor/fixed_thread_pool.rb} +6 -7
- data/lib/concurrent/{immediate_executor.rb → executor/immediate_executor.rb} +5 -5
- data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
- data/lib/concurrent/{java_fixed_thread_pool.rb → executor/java_fixed_thread_pool.rb} +7 -11
- data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
- data/lib/concurrent/{java_thread_pool_executor.rb → executor/java_thread_pool_executor.rb} +66 -77
- data/lib/concurrent/executor/one_by_one.rb +65 -0
- data/lib/concurrent/{per_thread_executor.rb → executor/per_thread_executor.rb} +4 -4
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
- data/lib/concurrent/{ruby_fixed_thread_pool.rb → executor/ruby_fixed_thread_pool.rb} +5 -4
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +72 -0
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +282 -0
- data/lib/concurrent/{ruby_thread_pool_worker.rb → executor/ruby_thread_pool_worker.rb} +6 -6
- data/lib/concurrent/{safe_task_executor.rb → executor/safe_task_executor.rb} +20 -13
- data/lib/concurrent/executor/single_thread_executor.rb +35 -0
- data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
- data/lib/concurrent/executor/timer_set.rb +138 -0
- data/lib/concurrent/executors.rb +9 -0
- data/lib/concurrent/future.rb +39 -40
- data/lib/concurrent/ivar.rb +22 -15
- data/lib/concurrent/mvar.rb +2 -1
- data/lib/concurrent/obligation.rb +9 -3
- data/lib/concurrent/observable.rb +33 -0
- data/lib/concurrent/options_parser.rb +46 -0
- data/lib/concurrent/promise.rb +23 -24
- data/lib/concurrent/scheduled_task.rb +21 -45
- data/lib/concurrent/timer_task.rb +204 -126
- data/lib/concurrent/tvar.rb +1 -1
- data/lib/concurrent/utilities.rb +3 -36
- data/lib/concurrent/{processor_count.rb → utility/processor_count.rb} +1 -1
- data/lib/concurrent/utility/timeout.rb +36 -0
- data/lib/concurrent/utility/timer.rb +21 -0
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent_ruby_ext.bundle +0 -0
- data/spec/concurrent/{actor_context_spec.rb → actor/actor_context_spec.rb} +0 -8
- data/spec/concurrent/{actor_ref_shared.rb → actor/actor_ref_shared.rb} +9 -59
- data/spec/concurrent/{actor_spec.rb → actor/actor_spec.rb} +43 -41
- data/spec/concurrent/{postable_shared.rb → actor/postable_shared.rb} +0 -0
- data/spec/concurrent/actor/simple_actor_ref_spec.rb +135 -0
- data/spec/concurrent/agent_spec.rb +160 -71
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +172 -0
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +186 -0
- data/spec/concurrent/{condition_spec.rb → atomic/condition_spec.rb} +2 -2
- data/spec/concurrent/{copy_on_notify_observer_set_spec.rb → atomic/copy_on_notify_observer_set_spec.rb} +0 -0
- data/spec/concurrent/{copy_on_write_observer_set_spec.rb → atomic/copy_on_write_observer_set_spec.rb} +0 -0
- data/spec/concurrent/atomic/count_down_latch_spec.rb +151 -0
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +248 -0
- data/spec/concurrent/{event_spec.rb → atomic/event_spec.rb} +18 -3
- data/spec/concurrent/{observer_set_shared.rb → atomic/observer_set_shared.rb} +15 -6
- data/spec/concurrent/{thread_local_var_spec.rb → atomic/thread_local_var_spec.rb} +0 -0
- data/spec/concurrent/channel/buffered_channel_spec.rb +1 -1
- data/spec/concurrent/channel/channel_spec.rb +6 -4
- data/spec/concurrent/channel/probe_spec.rb +37 -9
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +2 -2
- data/spec/concurrent/{channel → collection}/blocking_ring_buffer_spec.rb +0 -0
- data/spec/concurrent/collection/priority_queue_spec.rb +317 -0
- data/spec/concurrent/{channel → collection}/ring_buffer_spec.rb +0 -0
- data/spec/concurrent/configuration_spec.rb +4 -70
- data/spec/concurrent/dereferenceable_shared.rb +5 -4
- data/spec/concurrent/exchanger_spec.rb +10 -5
- data/spec/concurrent/{cached_thread_pool_shared.rb → executor/cached_thread_pool_shared.rb} +15 -37
- data/spec/concurrent/{fixed_thread_pool_shared.rb → executor/fixed_thread_pool_shared.rb} +0 -0
- data/spec/concurrent/{global_thread_pool_shared.rb → executor/global_thread_pool_shared.rb} +10 -8
- data/spec/concurrent/{immediate_executor_spec.rb → executor/immediate_executor_spec.rb} +0 -0
- data/spec/concurrent/{java_cached_thread_pool_spec.rb → executor/java_cached_thread_pool_spec.rb} +1 -21
- data/spec/concurrent/{java_fixed_thread_pool_spec.rb → executor/java_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +21 -0
- data/spec/concurrent/{java_thread_pool_executor_spec.rb → executor/java_thread_pool_executor_spec.rb} +0 -0
- data/spec/concurrent/{per_thread_executor_spec.rb → executor/per_thread_executor_spec.rb} +0 -4
- data/spec/concurrent/{ruby_cached_thread_pool_spec.rb → executor/ruby_cached_thread_pool_spec.rb} +1 -1
- data/spec/concurrent/{ruby_fixed_thread_pool_spec.rb → executor/ruby_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +18 -0
- data/spec/concurrent/{ruby_thread_pool_executor_spec.rb → executor/ruby_thread_pool_executor_spec.rb} +12 -24
- data/spec/concurrent/executor/safe_task_executor_spec.rb +103 -0
- data/spec/concurrent/{thread_pool_class_cast_spec.rb → executor/thread_pool_class_cast_spec.rb} +12 -0
- data/spec/concurrent/{thread_pool_executor_shared.rb → executor/thread_pool_executor_shared.rb} +0 -0
- data/spec/concurrent/{thread_pool_shared.rb → executor/thread_pool_shared.rb} +84 -119
- data/spec/concurrent/executor/timer_set_spec.rb +183 -0
- data/spec/concurrent/future_spec.rb +12 -0
- data/spec/concurrent/ivar_spec.rb +11 -1
- data/spec/concurrent/observable_shared.rb +173 -0
- data/spec/concurrent/observable_spec.rb +51 -0
- data/spec/concurrent/options_parser_spec.rb +71 -0
- data/spec/concurrent/runnable_shared.rb +6 -0
- data/spec/concurrent/scheduled_task_spec.rb +60 -40
- data/spec/concurrent/timer_task_spec.rb +130 -144
- data/spec/concurrent/{processor_count_spec.rb → utility/processor_count_spec.rb} +0 -0
- data/spec/concurrent/{utilities_spec.rb → utility/timeout_spec.rb} +0 -0
- data/spec/concurrent/utility/timer_spec.rb +52 -0
- metadata +147 -108
- data/lib/concurrent/actor_context.rb +0 -31
- data/lib/concurrent/actor_ref.rb +0 -39
- data/lib/concurrent/atomic.rb +0 -121
- data/lib/concurrent/channel/probe.rb +0 -19
- data/lib/concurrent/count_down_latch.rb +0 -60
- data/lib/concurrent/event.rb +0 -80
- data/lib/concurrent/java_cached_thread_pool.rb +0 -45
- data/lib/concurrent/ruby_cached_thread_pool.rb +0 -37
- data/lib/concurrent/ruby_thread_pool_executor.rb +0 -268
- data/lib/concurrent/simple_actor_ref.rb +0 -124
- data/lib/concurrent/thread_pool_executor.rb +0 -30
- data/spec/concurrent/atomic_spec.rb +0 -201
- data/spec/concurrent/count_down_latch_spec.rb +0 -125
- data/spec/concurrent/safe_task_executor_spec.rb +0 -58
- data/spec/concurrent/simple_actor_ref_spec.rb +0 -219
@@ -1,124 +0,0 @@
|
|
1
|
-
require 'thread'
|
2
|
-
|
3
|
-
require 'concurrent/actor_ref'
|
4
|
-
require 'concurrent/event'
|
5
|
-
require 'concurrent/ivar'
|
6
|
-
|
7
|
-
module Concurrent
|
8
|
-
|
9
|
-
class SimpleActorRef
|
10
|
-
include ActorRef
|
11
|
-
|
12
|
-
def initialize(actor, opts = {})
|
13
|
-
@actor = actor
|
14
|
-
@mutex = Mutex.new
|
15
|
-
@queue = Queue.new
|
16
|
-
@thread = nil
|
17
|
-
@stop_event = Event.new
|
18
|
-
@abort_on_exception = opts.fetch(:abort_on_exception, true)
|
19
|
-
@reset_on_error = opts.fetch(:reset_on_error, true)
|
20
|
-
@exception_class = opts.fetch(:rescue_exception, false) ? Exception : StandardError
|
21
|
-
@observers = CopyOnNotifyObserverSet.new
|
22
|
-
|
23
|
-
@actor.define_singleton_method(:shutdown, &method(:set_stop_event))
|
24
|
-
end
|
25
|
-
|
26
|
-
def running?
|
27
|
-
! @stop_event.set?
|
28
|
-
end
|
29
|
-
|
30
|
-
def shutdown?
|
31
|
-
@stop_event.set?
|
32
|
-
end
|
33
|
-
|
34
|
-
def post(*msg, &block)
|
35
|
-
raise ArgumentError.new('message cannot be empty') if msg.empty?
|
36
|
-
@mutex.synchronize do
|
37
|
-
supervise unless shutdown?
|
38
|
-
end
|
39
|
-
ivar = IVar.new
|
40
|
-
@queue.push(Message.new(msg, ivar, block))
|
41
|
-
ivar
|
42
|
-
end
|
43
|
-
|
44
|
-
def post!(seconds, *msg)
|
45
|
-
raise Concurrent::TimeoutError if seconds == 0
|
46
|
-
ivar = self.post(*msg)
|
47
|
-
ivar.value(seconds)
|
48
|
-
if ivar.incomplete?
|
49
|
-
raise Concurrent::TimeoutError
|
50
|
-
elsif ivar.reason
|
51
|
-
raise ivar.reason
|
52
|
-
end
|
53
|
-
ivar.value
|
54
|
-
end
|
55
|
-
|
56
|
-
def shutdown
|
57
|
-
@mutex.synchronize do
|
58
|
-
return if shutdown?
|
59
|
-
if @thread && @thread.alive?
|
60
|
-
@thread.kill
|
61
|
-
@actor.on_shutdown
|
62
|
-
end
|
63
|
-
@stop_event.set
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def join(timeout = nil)
|
68
|
-
@stop_event.wait(timeout)
|
69
|
-
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
Message = Struct.new(:payload, :ivar, :callback)
|
74
|
-
|
75
|
-
def set_stop_event
|
76
|
-
@stop_event.set
|
77
|
-
end
|
78
|
-
|
79
|
-
def supervise
|
80
|
-
if @thread.nil?
|
81
|
-
@actor.on_start
|
82
|
-
@thread = new_worker_thread
|
83
|
-
elsif ! @thread.alive?
|
84
|
-
@actor.on_reset
|
85
|
-
@thread = new_worker_thread
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def new_worker_thread
|
90
|
-
Thread.new do
|
91
|
-
Thread.current.abort_on_exception = @abort_on_exception
|
92
|
-
run_message_loop
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def run_message_loop
|
97
|
-
loop do
|
98
|
-
message = @queue.pop
|
99
|
-
result = ex = nil
|
100
|
-
|
101
|
-
begin
|
102
|
-
result = @actor.receive(*message.payload)
|
103
|
-
rescue @exception_class => ex
|
104
|
-
@actor.on_error(Time.now, message.payload, ex)
|
105
|
-
@actor.on_reset if @reset_on_error
|
106
|
-
ensure
|
107
|
-
now = Time.now
|
108
|
-
message.ivar.complete(ex.nil?, result, ex)
|
109
|
-
|
110
|
-
begin
|
111
|
-
message.callback.call(now, result, ex) if message.callback
|
112
|
-
rescue @exception_class => ex
|
113
|
-
# suppress
|
114
|
-
end
|
115
|
-
|
116
|
-
observers.notify_observers(now, message.payload, result, ex)
|
117
|
-
end
|
118
|
-
|
119
|
-
break if @stop_event.set?
|
120
|
-
end
|
121
|
-
@actor.on_shutdown
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'concurrent/ruby_thread_pool_executor'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
if RUBY_PLATFORM == 'java'
|
6
|
-
require 'concurrent/java_thread_pool_executor'
|
7
|
-
# @!macro [attach] thread_pool_executor
|
8
|
-
#
|
9
|
-
# A thread pool...
|
10
|
-
#
|
11
|
-
# The API and behavior of this class are based on Java's +ThreadPoolExecutor+
|
12
|
-
#
|
13
|
-
# @note When running on the JVM (JRuby) this class will inherit from +JavaThreadPoolExecutor+.
|
14
|
-
# On all other platforms it will inherit from +RubyThreadPoolExecutor+.
|
15
|
-
#
|
16
|
-
# @see Concurrent::RubyThreadPoolExecutor
|
17
|
-
# @see Concurrent::JavaThreadPoolExecutor
|
18
|
-
#
|
19
|
-
# @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
|
20
|
-
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html
|
21
|
-
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
|
22
|
-
# @see http://stackoverflow.com/questions/17957382/fixedthreadpool-vs-fixedthreadpool-the-lesser-of-two-evils
|
23
|
-
class ThreadPoolExecutor < JavaThreadPoolExecutor
|
24
|
-
end
|
25
|
-
else
|
26
|
-
# @!macro thread_pool_executor
|
27
|
-
class ThreadPoolExecutor < RubyThreadPoolExecutor
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,201 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
describe AtomicFixnum do
|
6
|
-
|
7
|
-
context 'construction' do
|
8
|
-
|
9
|
-
it 'sets the initial value' do
|
10
|
-
AtomicFixnum.new(10).value.should eq 10
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'defaults the initial value to zero' do
|
14
|
-
AtomicFixnum.new.value.should eq 0
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'raises en exception if the initial value is not a Fixnum' do
|
18
|
-
lambda {
|
19
|
-
AtomicFixnum.new(10.01)
|
20
|
-
}.should raise_error(ArgumentError)
|
21
|
-
end
|
22
|
-
|
23
|
-
if jruby?
|
24
|
-
|
25
|
-
it 'uses Java AtomicLong' do
|
26
|
-
mutex = double('mutex')
|
27
|
-
Mutex.stub(:new).with(no_args).and_return(mutex)
|
28
|
-
mutex.should_not_receive(:synchronize)
|
29
|
-
AtomicFixnum.new.value
|
30
|
-
end
|
31
|
-
|
32
|
-
else
|
33
|
-
|
34
|
-
it 'is synchronized' do
|
35
|
-
mutex = double('mutex')
|
36
|
-
Mutex.stub(:new).with(no_args).and_return(mutex)
|
37
|
-
mutex.should_receive(:synchronize)
|
38
|
-
AtomicFixnum.new.value
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
context '#value' do
|
46
|
-
|
47
|
-
it 'returns the current value' do
|
48
|
-
counter = AtomicFixnum.new(10)
|
49
|
-
counter.value.should eq 10
|
50
|
-
counter.increment
|
51
|
-
counter.value.should eq 11
|
52
|
-
counter.decrement
|
53
|
-
counter.value.should eq 10
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
context '#value=' do
|
58
|
-
|
59
|
-
it 'sets the #value to the given `Fixnum`' do
|
60
|
-
atomic = AtomicFixnum.new(0)
|
61
|
-
atomic.value = 10
|
62
|
-
atomic.value.should eq 10
|
63
|
-
end
|
64
|
-
|
65
|
-
it 'returns the new value' do
|
66
|
-
atomic = AtomicFixnum.new(0)
|
67
|
-
(atomic.value = 10).should eq 10
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'raises and exception if the value is not a `Fixnum`' do
|
71
|
-
atomic = AtomicFixnum.new(0)
|
72
|
-
expect {
|
73
|
-
atomic.value = 'foo'
|
74
|
-
}.to raise_error(ArgumentError)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context '#increment' do
|
79
|
-
|
80
|
-
it 'increases the value by one' do
|
81
|
-
counter = AtomicFixnum.new(10)
|
82
|
-
3.times{ counter.increment }
|
83
|
-
counter.value.should eq 13
|
84
|
-
end
|
85
|
-
|
86
|
-
it 'returns the new value' do
|
87
|
-
counter = AtomicFixnum.new(10)
|
88
|
-
counter.increment.should eq 11
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'is aliased as #up' do
|
92
|
-
AtomicFixnum.new(10).up.should eq 11
|
93
|
-
end
|
94
|
-
|
95
|
-
if jruby?
|
96
|
-
|
97
|
-
it 'does not use Mutex class' do
|
98
|
-
mutex = double('mutex')
|
99
|
-
Mutex.stub(:new).with(no_args).and_return(mutex)
|
100
|
-
mutex.should_not_receive(:synchronize)
|
101
|
-
AtomicFixnum.new.increment
|
102
|
-
end
|
103
|
-
|
104
|
-
else
|
105
|
-
|
106
|
-
it 'is synchronized' do
|
107
|
-
mutex = double('mutex')
|
108
|
-
Mutex.stub(:new).with(no_args).and_return(mutex)
|
109
|
-
mutex.should_receive(:synchronize)
|
110
|
-
AtomicFixnum.new.increment
|
111
|
-
end
|
112
|
-
|
113
|
-
end
|
114
|
-
|
115
|
-
end
|
116
|
-
|
117
|
-
context '#decrement' do
|
118
|
-
|
119
|
-
it 'decreases the value by one' do
|
120
|
-
counter = AtomicFixnum.new(10)
|
121
|
-
3.times{ counter.decrement }
|
122
|
-
counter.value.should eq 7
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'returns the new value' do
|
126
|
-
counter = AtomicFixnum.new(10)
|
127
|
-
counter.decrement.should eq 9
|
128
|
-
end
|
129
|
-
|
130
|
-
it 'is aliased as #down' do
|
131
|
-
AtomicFixnum.new(10).down.should eq 9
|
132
|
-
end
|
133
|
-
|
134
|
-
if jruby?
|
135
|
-
|
136
|
-
it 'does not use Mutex class' do
|
137
|
-
mutex = double('mutex')
|
138
|
-
Mutex.stub(:new).with(no_args).and_return(mutex)
|
139
|
-
mutex.should_not_receive(:synchronize)
|
140
|
-
AtomicFixnum.new.decrement
|
141
|
-
end
|
142
|
-
|
143
|
-
else
|
144
|
-
|
145
|
-
it 'is synchronized' do
|
146
|
-
mutex = double('mutex')
|
147
|
-
Mutex.stub(:new).with(no_args).and_return(mutex)
|
148
|
-
mutex.should_receive(:synchronize)
|
149
|
-
AtomicFixnum.new.decrement
|
150
|
-
end
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
end
|
155
|
-
|
156
|
-
context '#compare_and_set' do
|
157
|
-
|
158
|
-
it 'returns false if the value is not found' do
|
159
|
-
AtomicFixnum.new(14).compare_and_set(2, 14).should eq false
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'returns true if the value is found' do
|
163
|
-
AtomicFixnum.new(14).compare_and_set(14, 2).should eq true
|
164
|
-
end
|
165
|
-
|
166
|
-
it 'sets if the value is found' do
|
167
|
-
f = AtomicFixnum.new(14)
|
168
|
-
f.compare_and_set(14, 2)
|
169
|
-
f.value.should eq 2
|
170
|
-
end
|
171
|
-
|
172
|
-
it 'does not set if the value is not found' do
|
173
|
-
f = AtomicFixnum.new(14)
|
174
|
-
f.compare_and_set(2, 12)
|
175
|
-
f.value.should eq 14
|
176
|
-
end
|
177
|
-
|
178
|
-
if jruby?
|
179
|
-
|
180
|
-
it 'does not use Mutex class' do
|
181
|
-
mutex = double('mutex')
|
182
|
-
Mutex.stub(:new).with(no_args).and_return(mutex)
|
183
|
-
mutex.should_not_receive(:synchronize)
|
184
|
-
AtomicFixnum.new(14).compare_and_set(14, 2)
|
185
|
-
end
|
186
|
-
|
187
|
-
else
|
188
|
-
|
189
|
-
it 'is synchronized' do
|
190
|
-
mutex = double('mutex')
|
191
|
-
Mutex.stub(:new).with(no_args).and_return(mutex)
|
192
|
-
mutex.should_receive(:synchronize)
|
193
|
-
AtomicFixnum.new(14).compare_and_set(14, 2)
|
194
|
-
end
|
195
|
-
|
196
|
-
end
|
197
|
-
|
198
|
-
end
|
199
|
-
|
200
|
-
end
|
201
|
-
end
|
@@ -1,125 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
describe CountDownLatch do
|
6
|
-
|
7
|
-
let(:latch) { CountDownLatch.new(3) }
|
8
|
-
let(:zero_count_latch) { CountDownLatch.new(0) }
|
9
|
-
|
10
|
-
context '#initialize' do
|
11
|
-
|
12
|
-
it 'raises an exception if the initial count is less than zero' do
|
13
|
-
expect {
|
14
|
-
CountDownLatch.new(-1)
|
15
|
-
}.to raise_error(ArgumentError)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'raises an exception if the initial count is not an integer' do
|
19
|
-
expect {
|
20
|
-
CountDownLatch.new('foo')
|
21
|
-
}.to raise_error(ArgumentError)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe '#count' do
|
26
|
-
|
27
|
-
it 'should be the value passed to the constructor' do
|
28
|
-
latch.count.should eq 3
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'should be decreased after every count down' do
|
32
|
-
latch.count_down
|
33
|
-
latch.count.should eq 2
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'should not go below zero' do
|
37
|
-
5.times { latch.count_down }
|
38
|
-
latch.count.should eq 0
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe '#wait' do
|
43
|
-
|
44
|
-
context 'count set to zero' do
|
45
|
-
it 'should return true immediately' do
|
46
|
-
result = zero_count_latch.wait
|
47
|
-
result.should be_true
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'should return true immediately with timeout' do
|
51
|
-
result = zero_count_latch.wait(5)
|
52
|
-
result.should be_true
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
context 'non zero count' do
|
57
|
-
|
58
|
-
it 'should block thread until counter is set to zero' do
|
59
|
-
3.times do
|
60
|
-
Thread.new { sleep(0.1); latch.count_down }
|
61
|
-
end
|
62
|
-
|
63
|
-
result = latch.wait
|
64
|
-
result.should be_true
|
65
|
-
latch.count.should eq 0
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'should block until counter is set to zero with timeout' do
|
69
|
-
3.times do
|
70
|
-
Thread.new { sleep(0.1); latch.count_down }
|
71
|
-
end
|
72
|
-
|
73
|
-
result = latch.wait(1)
|
74
|
-
result.should be_true
|
75
|
-
latch.count.should eq 0
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'should block until timeout and return false when counter is not set to zero' do
|
80
|
-
result = latch.wait(0.1)
|
81
|
-
result.should be_false
|
82
|
-
latch.count.should eq 3
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
context 'spurious wake ups' do
|
88
|
-
|
89
|
-
before(:each) do
|
90
|
-
def latch.simulate_spurious_wake_up
|
91
|
-
@mutex.synchronize do
|
92
|
-
@condition.signal
|
93
|
-
@condition.broadcast
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'should resist to spurious wake ups without timeout' do
|
99
|
-
@expected = false
|
100
|
-
Thread.new { latch.wait; @expected = true }
|
101
|
-
|
102
|
-
sleep(0.1)
|
103
|
-
latch.simulate_spurious_wake_up
|
104
|
-
|
105
|
-
sleep(0.1)
|
106
|
-
@expected.should be_false
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'should resist to spurious wake ups with timeout' do
|
110
|
-
@expected = false
|
111
|
-
Thread.new { latch.wait(0.5); @expected = true }
|
112
|
-
|
113
|
-
sleep(0.1)
|
114
|
-
latch.simulate_spurious_wake_up
|
115
|
-
|
116
|
-
sleep(0.1)
|
117
|
-
@expected.should be_false
|
118
|
-
|
119
|
-
sleep(0.4)
|
120
|
-
@expected.should be_true
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
end
|
125
|
-
end
|