Skip to content

Commit ad9a57b

Browse files
committed
Merge pull request #262 from ruby-concurrency/refactor/tests
Fix Intermittently Failing Tests
2 parents 2859060 + eb5c8d5 commit ad9a57b

File tree

9 files changed

+278
-112
lines changed

9 files changed

+278
-112
lines changed

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ source 'https://rubygems.org'
33
gemspec name: 'concurrent-ruby'
44

55
group :development do
6-
gem 'rake', '~> 10.3.2'
6+
gem 'rake', '~> 10.4.2'
77
gem 'rake-compiler', '~> 0.9.5'
88
gem 'gem-compiler', '~> 0.3.0'
99
end

lib/concurrent/exchanger.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
11
module Concurrent
2+
3+
# A synchronization point at which threads can pair and swap elements within
4+
# pairs. Each thread presents some object on entry to the exchange method,
5+
# matches with a partner thread, and receives its partner's object on return.
6+
#
7+
# Uses `MVar` to manage synchronization of the individual elements.
8+
# Since `MVar` is also a `Dereferenceable`, the exchanged values support all
9+
# dereferenceable options. The constructor options hash will be passed to
10+
# the `MVar` constructors.
11+
#
12+
# @see Concurrent::MVar
13+
# @see Concurrent::Dereferenceable
14+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html java.util.concurrent.Exchanger
215
class Exchanger
316

417
EMPTY = Object.new
518

19+
# Create a new `Exchanger` object.
20+
#
21+
# @param [Hash] opts the options controlling how the managed references
22+
# will be processed
623
def initialize(opts = {})
724
@first = MVar.new(EMPTY, opts)
825
@second = MVar.new(MVar::EMPTY, opts)
926
end
1027

28+
# Waits for another thread to arrive at this exchange point (unless the
29+
# current thread is interrupted), and then transfers the given object to
30+
# it, receiving its object in return.
31+
#
1132
# @param [Object] value the value to exchange with an other thread
1233
# @param [Numeric] timeout the maximum time in second to wait for one other
1334
# thread. nil (default value) means no timeout

lib/concurrent/executor/executor.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ def auto_terminate?
6969
def enable_at_exit_handler!(opts = {})
7070
if opts.fetch(:stop_on_exit, true)
7171
@auto_terminate = true
72-
if RUBY_PLATFORM == 'java'
73-
create_java_at_exit_handler!(self)
72+
if RUBY_PLATFORM == 'ruby'
73+
create_mri_at_exit_handler!(self.object_id)
7474
else
75-
create_ruby_at_exit_handler!(self.object_id)
75+
create_at_exit_handler!(self)
7676
end
7777
end
7878
end
7979

80-
def create_ruby_at_exit_handler!(id)
80+
def create_mri_at_exit_handler!(id)
8181
at_exit do
8282
if Concurrent.auto_terminate_all_executors?
8383
this = ObjectSpace._id2ref(id)
@@ -86,7 +86,7 @@ def create_ruby_at_exit_handler!(id)
8686
end
8787
end
8888

89-
def create_java_at_exit_handler!(this)
89+
def create_at_exit_handler!(this)
9090
at_exit do
9191
this.kill if Concurrent.auto_terminate_all_executors?
9292
end

lib/concurrent/utility/monotonic_time.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,22 @@ def monotonic_time
5555
GLOBAL_MONOTONIC_CLOCK.get_time
5656
end
5757
module_function :monotonic_time
58+
59+
# Runs the given block and returns the number of seconds that elapsed.
60+
#
61+
# @yield the block to run and time
62+
# @return [Float] the number of seconds the block took to run
63+
#
64+
# @raise [ArgumentError] when no block given
65+
#
66+
# @!macro monotonic_clock_warning
67+
def monotonic_interval
68+
raise ArgumentError.new('no block given') unless block_given?
69+
start_time = GLOBAL_MONOTONIC_CLOCK.get_time
70+
yield
71+
GLOBAL_MONOTONIC_CLOCK.get_time - start_time
72+
end
73+
module_function :monotonic_interval
5874
end
5975

6076
__END__

spec/concurrent/agent_spec.rb

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

1010
subject { Agent.new(0, executor: executor) }
1111

12+
after(:each) do
13+
executor.kill
14+
end
15+
1216
let(:observer) do
1317
Class.new do
1418
attr_reader :value
@@ -196,17 +200,12 @@ def trigger_observable(observable)
196200
context '#await' do
197201

198202
it 'waits until already sent updates are done' do
199-
fn = false
200-
subject.post { fn = true; sleep 0.1 }
201-
subject.await
202-
expect(fn).to be_truthy
203-
end
204-
205-
it 'does not waits until updates sent after are done' do
206-
fn = false
203+
actual = Concurrent::AtomicBoolean.new(false)
204+
latch = Concurrent::CountDownLatch.new
205+
subject.post { latch.count_down; sleep(0.1); actual.make_true }
206+
latch.wait(1)
207207
subject.await
208-
subject.post { fn = true; sleep 0.1 }
209-
expect(fn).to be_falsey
208+
expect(actual.value).to be true
210209
end
211210

212211
it 'does not alter the value' do

0 commit comments

Comments
 (0)