synchronicity 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ vendor/ruby
@@ -0,0 +1,4 @@
1
+ # develop
2
+
3
+ # v1.0.0
4
+ * First public release, imported from CountDownLatch
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in synchronicity.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,43 @@
1
+ # Synchronicity [ ![Build status](http://travis-ci.org/benlangfeld/synchronicity.png) ](http://travis-ci.org/benlangfeld/synchronicity)
2
+ Concurrency aids for Ruby, mostly around thread synchronisation. Includes:
3
+
4
+ * CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes
5
+
6
+ ## Installation
7
+ gem install synchronicity
8
+
9
+ ## Usage
10
+ ```ruby
11
+ require 'synchronicity'
12
+
13
+ include Synchronicity
14
+
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
+
27
+ ## Links
28
+ * [Source](https://github.com/benlangfeld/synchronicity)
29
+ * [Documentation](http://rdoc.info/github/benlangfeld/synchronicity/master)
30
+ * [Bug Tracker](https://github.com/benlangfeld/synchronicity/issues)
31
+
32
+ ## Note on Patches/Pull Requests
33
+
34
+ * Fork the project.
35
+ * Make your feature addition or bug fix.
36
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
37
+ * Commit, do not mess with rakefile, version, or history.
38
+ * 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
39
+ * Send me a pull request. Bonus points for topic branches.
40
+
41
+ ## Copyright
42
+
43
+ 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,2 @@
1
+ require "synchronicity/version"
2
+ require "synchronicity/countdownlatch"
@@ -0,0 +1,97 @@
1
+ require "synchronicity/version"
2
+
3
+ require 'thread'
4
+ require 'timeout'
5
+
6
+ module Synchronicity
7
+ ##
8
+ # A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
9
+ #
10
+ # Mirrors the Java implementation: http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html
11
+ #
12
+ # @author Ben Langfeld
13
+ # @author Tuomas Kareinen (derivative): https://gist.github.com/739662
14
+ #
15
+ # @example Count down from 2 in 2 seconds, with a timeout of 10 seconds
16
+ # latch = CountDownLatch.new 2
17
+ #
18
+ # Thread.new do
19
+ # 2.times do
20
+ # sleep 1
21
+ # latch.countdown!
22
+ # end
23
+ # end
24
+ #
25
+ # latch.wait 10
26
+ #
27
+ class CountDownLatch
28
+ ##
29
+ # Create a new CountDownLatch
30
+ # @param [Integer] count the number of times #countdown! must be invoked before threads can pass through #wait
31
+ #
32
+ # @raise [ArgumentError] if the count is less than zero
33
+ #
34
+ def initialize(count)
35
+ raise ArgumentError if count < 0
36
+ @count = count
37
+ @mutex = Mutex.new
38
+ @conditional = ConditionVariable.new
39
+ end
40
+
41
+ ##
42
+ # Decrements the count of the latch, releasing all waiting threads if the count reaches zero.
43
+ # * 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.
44
+ # * If the current count equals zero then nothing happens.
45
+ #
46
+ def countdown!
47
+ @mutex.synchronize do
48
+ @count -= 1 if @count > 0
49
+ @conditional.broadcast if @count == 0
50
+ end
51
+ end
52
+
53
+ ##
54
+ # Returns the current count.
55
+ # This method is typically used for debugging and testing purposes.
56
+ #
57
+ # @return [Integer]
58
+ #
59
+ def count
60
+ @mutex.synchronize { @count }
61
+ end
62
+
63
+ ##
64
+ # Returns a string identifying this latch, as well as its state. The state, in brackets, includes the String "Count =" followed by the current count.
65
+ #
66
+ # @return [String]
67
+ #
68
+ def to_s
69
+ super.insert -2, " (Count = #{count})"
70
+ end
71
+
72
+ ##
73
+ # Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted.
74
+ # If the current count is zero then this method returns immediately.
75
+ # 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:
76
+ # * The count reaches zero due to invocations of the countdown! method; or
77
+ # * Some other thread interrupts the current thread; or
78
+ # * The specified waiting time elapses.
79
+ #
80
+ # @param [Integer] timeout the maximum time to wait in seconds
81
+ #
82
+ # @return [Boolean] true if the count reached zero and false if the waiting time elapsed before the count reached zero
83
+ #
84
+ def wait(timeout = nil)
85
+ begin
86
+ Timeout::timeout timeout do
87
+ @mutex.synchronize do
88
+ @conditional.wait @mutex if @count > 0
89
+ end
90
+ end
91
+ true
92
+ rescue Timeout::Error
93
+ false
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,3 @@
1
+ module Synchronicity
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,152 @@
1
+ require 'minitest/autorun'
2
+ require 'synchronicity'
3
+
4
+ module Synchronicity
5
+ describe CountDownLatch do
6
+ it "requires a positive count" do
7
+ assert_raises(ArgumentError) { CountDownLatch.new(-1) }
8
+ end
9
+
10
+ describe "#wait" do
11
+ describe "counting down from 1" do
12
+ before do
13
+ @latch = CountDownLatch.new 1
14
+ @name = :foo
15
+ end
16
+
17
+ it "blocks until counted down in another thread" do
18
+ Thread.new do
19
+ @name = :bar
20
+ @latch.countdown!
21
+ end
22
+ @latch.wait
23
+ @latch.count.must_equal 0
24
+ @name.must_equal :bar
25
+ end
26
+
27
+ it "blocks another thread until counted down" do
28
+ Thread.new do
29
+ @latch.wait
30
+ @latch.count.must_equal 0
31
+ @name.must_equal :bar
32
+ end
33
+ @name = :bar
34
+ @latch.countdown!
35
+ end
36
+
37
+ it "returns true if counted down" do
38
+ Thread.new { @latch.countdown! }
39
+ @latch.wait.must_equal true
40
+ end
41
+
42
+ it "returns true if timed out" do
43
+ @latch.wait(0.01).must_equal false
44
+ end
45
+ end
46
+
47
+ describe "counting down from zero" do
48
+ before do
49
+ @latch = CountDownLatch.new 0
50
+ end
51
+
52
+ it "does not wait" do
53
+ @latch.wait
54
+ @latch.count.must_equal 0
55
+ end
56
+ end
57
+
58
+ describe "counting down from 2" do
59
+ before do
60
+ @latch = CountDownLatch.new 2
61
+ @name = :foo
62
+ end
63
+
64
+ it "within a single thread" do
65
+ Thread.new do
66
+ @latch.countdown!
67
+ @name = :bar
68
+ @latch.countdown!
69
+ end
70
+ @latch.wait
71
+ @latch.count.must_equal 0
72
+ @name.must_equal :bar
73
+ end
74
+
75
+ it "within two parallel threads" do
76
+ Thread.new { @latch.countdown! }
77
+ Thread.new do
78
+ @name = :bar
79
+ @latch.countdown!
80
+ end
81
+ @latch.wait
82
+ @latch.count.must_equal 0
83
+ @name.must_equal :bar
84
+ end
85
+
86
+ it "within two chained threads" do
87
+ Thread.new do
88
+ @latch.countdown!
89
+ Thread.new do
90
+ @name = :bar
91
+ @latch.countdown!
92
+ end
93
+ end
94
+ @latch.wait
95
+ @latch.count.must_equal 0
96
+ @name.must_equal :bar
97
+ end
98
+ end
99
+
100
+ describe "with multiple waiters" do
101
+ before do
102
+ @proceed_latch = CountDownLatch.new 2
103
+ @check_latch = CountDownLatch.new 2
104
+ @results = {}
105
+ end
106
+
107
+ it "executes in the correct order" do
108
+ Thread.new do
109
+ @proceed_latch.wait
110
+ @results[:first] = 1
111
+ @check_latch.countdown!
112
+ end
113
+ Thread.new do
114
+ @proceed_latch.wait
115
+ @results[:second] = 2
116
+ @check_latch.countdown!
117
+ end
118
+ @results.must_equal({})
119
+ 2.times { @proceed_latch.countdown! }
120
+ @check_latch.wait
121
+ @proceed_latch.count.must_equal 0
122
+ @check_latch.count.must_equal 0
123
+ @results.must_equal :first => 1, :second => 2
124
+ end
125
+ end
126
+
127
+ describe "with interleaved latches" do
128
+ before do
129
+ @change_1_latch = CountDownLatch.new 1
130
+ @check_latch = CountDownLatch.new 1
131
+ @change_2_latch = CountDownLatch.new 1
132
+ @name = :foo
133
+ end
134
+
135
+ it "blocks the correct thread" do
136
+ Thread.new do
137
+ @name = :bar
138
+ @change_1_latch.countdown!
139
+ @check_latch.wait
140
+ @name = :man
141
+ @change_2_latch.countdown!
142
+ end
143
+ @change_1_latch.wait
144
+ @name.must_equal :bar
145
+ @check_latch.countdown!
146
+ @change_2_latch.wait
147
+ @name.must_equal :man
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,152 @@
1
+ require 'minitest/autorun'
2
+ require 'synchronicity'
3
+
4
+ module Synchronicity
5
+ describe CountDownLatch do
6
+ it "requires a positive count" do
7
+ assert_raises(ArgumentError) { CountDownLatch.new(-1) }
8
+ end
9
+
10
+ describe "#wait" do
11
+ describe "counting down from 1" do
12
+ before do
13
+ @latch = CountDownLatch.new 1
14
+ @name = :foo
15
+ end
16
+
17
+ it "blocks until counted down in another thread" do
18
+ Thread.new do
19
+ @name = :bar
20
+ @latch.countdown!
21
+ end
22
+ @latch.wait
23
+ @latch.count.must_equal 0
24
+ @name.must_equal :bar
25
+ end
26
+
27
+ it "blocks another thread until counted down" do
28
+ Thread.new do
29
+ @latch.wait
30
+ @latch.count.must_equal 0
31
+ @name.must_equal :bar
32
+ end
33
+ @name = :bar
34
+ @latch.countdown!
35
+ end
36
+
37
+ it "returns true if counted down" do
38
+ Thread.new { @latch.countdown! }
39
+ @latch.wait.must_equal true
40
+ end
41
+
42
+ it "returns true if timed out" do
43
+ @latch.wait(0.01).must_equal false
44
+ end
45
+ end
46
+
47
+ describe "counting down from zero" do
48
+ before do
49
+ @latch = CountDownLatch.new 0
50
+ end
51
+
52
+ it "does not wait" do
53
+ @latch.wait
54
+ @latch.count.must_equal 0
55
+ end
56
+ end
57
+
58
+ describe "counting down from 2" do
59
+ before do
60
+ @latch = CountDownLatch.new 2
61
+ @name = :foo
62
+ end
63
+
64
+ it "within a single thread" do
65
+ Thread.new do
66
+ @latch.countdown!
67
+ @name = :bar
68
+ @latch.countdown!
69
+ end
70
+ @latch.wait
71
+ @latch.count.must_equal 0
72
+ @name.must_equal :bar
73
+ end
74
+
75
+ it "within two parallel threads" do
76
+ Thread.new { @latch.countdown! }
77
+ Thread.new do
78
+ @name = :bar
79
+ @latch.countdown!
80
+ end
81
+ @latch.wait
82
+ @latch.count.must_equal 0
83
+ @name.must_equal :bar
84
+ end
85
+
86
+ it "within two chained threads" do
87
+ Thread.new do
88
+ @latch.countdown!
89
+ Thread.new do
90
+ @name = :bar
91
+ @latch.countdown!
92
+ end
93
+ end
94
+ @latch.wait
95
+ @latch.count.must_equal 0
96
+ @name.must_equal :bar
97
+ end
98
+ end
99
+
100
+ describe "with multiple waiters" do
101
+ before do
102
+ @proceed_latch = CountDownLatch.new 2
103
+ @check_latch = CountDownLatch.new 2
104
+ @results = {}
105
+ end
106
+
107
+ it "executes in the correct order" do
108
+ Thread.new do
109
+ @proceed_latch.wait
110
+ @results[:first] = 1
111
+ @check_latch.countdown!
112
+ end
113
+ Thread.new do
114
+ @proceed_latch.wait
115
+ @results[:second] = 2
116
+ @check_latch.countdown!
117
+ end
118
+ @results.must_equal({})
119
+ 2.times { @proceed_latch.countdown! }
120
+ @check_latch.wait
121
+ @proceed_latch.count.must_equal 0
122
+ @check_latch.count.must_equal 0
123
+ @results.must_equal :first => 1, :second => 2
124
+ end
125
+ end
126
+
127
+ describe "with interleaved latches" do
128
+ before do
129
+ @change_1_latch = CountDownLatch.new 1
130
+ @check_latch = CountDownLatch.new 1
131
+ @change_2_latch = CountDownLatch.new 1
132
+ @name = :foo
133
+ end
134
+
135
+ it "blocks the correct thread" do
136
+ Thread.new do
137
+ @name = :bar
138
+ @change_1_latch.countdown!
139
+ @check_latch.wait
140
+ @name = :man
141
+ @change_2_latch.countdown!
142
+ end
143
+ @change_1_latch.wait
144
+ @name.must_equal :bar
145
+ @check_latch.countdown!
146
+ @change_2_latch.wait
147
+ @name.must_equal :man
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "synchronicity/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "synchronicity"
7
+ s.version = Synchronicity::VERSION
8
+ s.authors = ["Ben Langfeld"]
9
+ s.email = ["ben@langfeld.me"]
10
+ s.homepage = "https://github.com/benlangfeld/synchronicity"
11
+ s.summary = %q{Concurrency aids for Ruby, mostly around thread synchronisation.}
12
+ s.description = %q{Includes CountDownLatch, 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
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: synchronicity
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ben Langfeld
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &2152173780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2152173780
25
+ - !ruby/object:Gem::Dependency
26
+ name: minitest
27
+ requirement: &2152171820 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2152171820
36
+ description: Includes CountDownLatch, a synchronization aid that allows one or more
37
+ threads to wait until a set of operations being performed in other threads completes
38
+ email:
39
+ - ben@langfeld.me
40
+ executables: []
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - CHANGELOG.md
46
+ - Gemfile
47
+ - LICENSE.txt
48
+ - README.md
49
+ - Rakefile
50
+ - lib/synchronicity.rb
51
+ - lib/synchronicity/countdownlatch.rb
52
+ - lib/synchronicity/version.rb
53
+ - spec/countdownlatch_spec.rb
54
+ - spec/synchronicity/countdownlatch_spec.rb
55
+ - synchronicity.gemspec
56
+ homepage: https://github.com/benlangfeld/synchronicity
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.10
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Concurrency aids for Ruby, mostly around thread synchronisation.
80
+ test_files:
81
+ - spec/countdownlatch_spec.rb
82
+ - spec/synchronicity/countdownlatch_spec.rb
83
+ has_rdoc: