countdownlatch 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in countdownlatch.gemspec
4
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Ben Langfeld, Tuomas Kareinen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,39 @@
1
+ # CountDownLatch [ ![Build status](http://travis-ci.org/benlangfeld/countdownlatch.png) ](http://travis-ci.org/benlangfeld/countdownlatch)
2
+ A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes
3
+
4
+ ## Installation
5
+ gem install countdownlatch
6
+
7
+ ## Usage
8
+ ```ruby
9
+ require 'countdownlatch'
10
+
11
+ latch = CountDownLatch.new 2
12
+
13
+ Thread.new do
14
+ 2.times do
15
+ sleep 1
16
+ latch.countdown!
17
+ end
18
+ end
19
+
20
+ latch.wait 10
21
+ ```
22
+
23
+ ## Links
24
+ * [Source](https://github.com/benlangfeld/countdownlatch)
25
+ * [Documentation](http://rdoc.info/github/benlangfeld/countdownlatch/master/CountDownLatch)
26
+ * [Bug Tracker](https://github.com/benlangfeld/countdownlatch/issues)
27
+
28
+ ## Note on Patches/Pull Requests
29
+
30
+ * Fork the project.
31
+ * Make your feature addition or bug fix.
32
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
33
+ * Commit, do not mess with rakefile, version, or history.
34
+ * If you want to have your own version, that is fine but bump version in a commit by itself so I can ignore when I pull
35
+ * Send me a pull request. Bonus points for topic branches.
36
+
37
+ ## Copyright
38
+
39
+ Copyright (c) 2011 Ben Langfeld, Tuomas Kareinen. MIT licence (see LICENSE for details).
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ task :default => :test
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << "spec"
8
+ t.test_files = FileList['spec/*_spec.rb']
9
+ t.verbose = true
10
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "countdownlatch/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "countdownlatch"
7
+ s.version = CountDownLatch::VERSION
8
+ s.authors = ["Ben Langfeld"]
9
+ s.email = ["ben@langfeld.me"]
10
+ s.homepage = "https://github.com/benlangfeld/countdownlatch"
11
+ s.summary = %q{3..2..1..GO!}
12
+ s.description = %q{A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_development_dependency 'rake'
20
+ s.add_development_dependency 'minitest'
21
+ end
@@ -0,0 +1,95 @@
1
+ require "countdownlatch/version"
2
+
3
+ require 'thread'
4
+ require 'timeout'
5
+
6
+ ##
7
+ # A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
8
+ #
9
+ # Mirrors the Java implementation: http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html
10
+ #
11
+ # @author Ben Langfeld
12
+ # @author Tuomas Kareinen (derivative): https://gist.github.com/739662
13
+ #
14
+ # @example Count down from 2 in 2 seconds, with a timeout of 10 seconds
15
+ # latch = CountDownLatch.new 2
16
+ #
17
+ # Thread.new do
18
+ # 2.times do
19
+ # sleep 1
20
+ # latch.countdown!
21
+ # end
22
+ # end
23
+ #
24
+ # latch.wait 10
25
+ #
26
+ class CountDownLatch
27
+ ##
28
+ # Create a new CountDownLatch
29
+ # @param [Integer] count the number of times #countdown! must be invoked before threads can pass through #wait
30
+ #
31
+ # @raise [ArgumentError] if the count is less than zero
32
+ #
33
+ def initialize(count)
34
+ raise ArgumentError if count < 0
35
+ @count = count
36
+ @mutex = Mutex.new
37
+ @conditional = ConditionVariable.new
38
+ end
39
+
40
+ ##
41
+ # Decrements the count of the latch, releasing all waiting threads if the count reaches zero.
42
+ # * If the current count is greater than zero then it is decremented. If the new count is zero then all waiting threads are re-enabled for thread scheduling purposes.
43
+ # * If the current count equals zero then nothing happens.
44
+ #
45
+ def countdown!
46
+ @mutex.synchronize do
47
+ @count -= 1 if @count > 0
48
+ @conditional.broadcast if @count == 0
49
+ end
50
+ end
51
+
52
+ ##
53
+ # Returns the current count.
54
+ # This method is typically used for debugging and testing purposes.
55
+ #
56
+ # @return [Integer]
57
+ #
58
+ def count
59
+ @mutex.synchronize { @count }
60
+ end
61
+
62
+ ##
63
+ # Returns a string identifying this latch, as well as its state. The state, in brackets, includes the String "Count =" followed by the current count.
64
+ #
65
+ # @return [String]
66
+ #
67
+ def to_s
68
+ super.insert -2, " (Count = #{count})"
69
+ end
70
+
71
+ ##
72
+ # Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted.
73
+ # If the current count is zero then this method returns immediately.
74
+ # If the current count is greater than zero then the current thread becomes disabled for thread scheduling purposes and lies dormant until one of three things happen:
75
+ # * The count reaches zero due to invocations of the countdown! method; or
76
+ # * Some other thread interrupts the current thread; or
77
+ # * The specified waiting time elapses.
78
+ #
79
+ # @param [Integer] timeout the maximum time to wait in seconds
80
+ #
81
+ # @return [Boolean] true if the count reached zero and false if the waiting time elapsed before the count reached zero
82
+ #
83
+ def wait(timeout = nil)
84
+ begin
85
+ Timeout::timeout timeout do
86
+ @mutex.synchronize do
87
+ @conditional.wait @mutex if @count > 0
88
+ end
89
+ end
90
+ true
91
+ rescue Timeout::Error
92
+ false
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,3 @@
1
+ class CountDownLatch
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,150 @@
1
+ require 'minitest/autorun'
2
+ require 'countdownlatch'
3
+
4
+ describe CountDownLatch do
5
+ it "requires a positive count" do
6
+ assert_raises(ArgumentError) { CountDownLatch.new(-1) }
7
+ end
8
+
9
+ describe "#wait" do
10
+ describe "counting down from 1" do
11
+ before do
12
+ @latch = CountDownLatch.new 1
13
+ @name = :foo
14
+ end
15
+
16
+ it "blocks until counted down in another thread" do
17
+ Thread.new do
18
+ @name = :bar
19
+ @latch.countdown!
20
+ end
21
+ @latch.wait
22
+ @latch.count.must_equal 0
23
+ @name.must_equal :bar
24
+ end
25
+
26
+ it "blocks another thread until counted down" do
27
+ Thread.new do
28
+ @latch.wait
29
+ @latch.count.must_equal 0
30
+ @name.must_equal :bar
31
+ end
32
+ @name = :bar
33
+ @latch.countdown!
34
+ end
35
+
36
+ it "returns true if counted down" do
37
+ Thread.new { @latch.countdown! }
38
+ @latch.wait.must_equal true
39
+ end
40
+
41
+ it "returns true if timed out" do
42
+ @latch.wait(0.01).must_equal false
43
+ end
44
+ end
45
+
46
+ describe "counting down from zero" do
47
+ before do
48
+ @latch = CountDownLatch.new 0
49
+ end
50
+
51
+ it "does not wait" do
52
+ @latch.wait
53
+ @latch.count.must_equal 0
54
+ end
55
+ end
56
+
57
+ describe "counting down from 2" do
58
+ before do
59
+ @latch = CountDownLatch.new 2
60
+ @name = :foo
61
+ end
62
+
63
+ it "within a single thread" do
64
+ Thread.new do
65
+ @latch.countdown!
66
+ @name = :bar
67
+ @latch.countdown!
68
+ end
69
+ @latch.wait
70
+ @latch.count.must_equal 0
71
+ @name.must_equal :bar
72
+ end
73
+
74
+ it "within two parallel threads" do
75
+ Thread.new { @latch.countdown! }
76
+ Thread.new do
77
+ @name = :bar
78
+ @latch.countdown!
79
+ end
80
+ @latch.wait
81
+ @latch.count.must_equal 0
82
+ @name.must_equal :bar
83
+ end
84
+
85
+ it "within two chained threads" do
86
+ Thread.new do
87
+ @latch.countdown!
88
+ Thread.new do
89
+ @name = :bar
90
+ @latch.countdown!
91
+ end
92
+ end
93
+ @latch.wait
94
+ @latch.count.must_equal 0
95
+ @name.must_equal :bar
96
+ end
97
+ end
98
+
99
+ describe "with multiple waiters" do
100
+ before do
101
+ @proceed_latch = CountDownLatch.new 2
102
+ @check_latch = CountDownLatch.new 2
103
+ @results = {}
104
+ end
105
+
106
+ it "executes in the correct order" do
107
+ Thread.new do
108
+ @proceed_latch.wait
109
+ @results[:first] = 1
110
+ @check_latch.countdown!
111
+ end
112
+ Thread.new do
113
+ @proceed_latch.wait
114
+ @results[:second] = 2
115
+ @check_latch.countdown!
116
+ end
117
+ @results.must_equal({})
118
+ 2.times { @proceed_latch.countdown! }
119
+ @check_latch.wait
120
+ @proceed_latch.count.must_equal 0
121
+ @check_latch.count.must_equal 0
122
+ @results.must_equal :first => 1, :second => 2
123
+ end
124
+ end
125
+
126
+ describe "with interleaved latches" do
127
+ before do
128
+ @change_1_latch = CountDownLatch.new 1
129
+ @check_latch = CountDownLatch.new 1
130
+ @change_2_latch = CountDownLatch.new 1
131
+ @name = :foo
132
+ end
133
+
134
+ it "blocks the correct thread" do
135
+ Thread.new do
136
+ @name = :bar
137
+ @change_1_latch.countdown!
138
+ @check_latch.wait
139
+ @name = :man
140
+ @change_2_latch.countdown!
141
+ end
142
+ @change_1_latch.wait
143
+ @name.must_equal :bar
144
+ @check_latch.countdown!
145
+ @change_2_latch.wait
146
+ @name.must_equal :man
147
+ end
148
+ end
149
+ end
150
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: countdownlatch
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Ben Langfeld
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-07-10 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rake
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: minitest
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :development
45
+ version_requirements: *id002
46
+ description: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes
47
+ email:
48
+ - ben@langfeld.me
49
+ executables: []
50
+
51
+ extensions: []
52
+
53
+ extra_rdoc_files: []
54
+
55
+ files:
56
+ - .gitignore
57
+ - Gemfile
58
+ - LICENSE.txt
59
+ - README.md
60
+ - Rakefile
61
+ - countdownlatch.gemspec
62
+ - lib/countdownlatch.rb
63
+ - lib/countdownlatch/version.rb
64
+ - spec/countdownlatch_spec.rb
65
+ has_rdoc: true
66
+ homepage: https://github.com/benlangfeld/countdownlatch
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options: []
71
+
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ requirements: []
91
+
92
+ rubyforge_project:
93
+ rubygems_version: 1.3.7
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: 3..2..1..GO!
97
+ test_files:
98
+ - spec/countdownlatch_spec.rb