splib 1.2 → 1.3

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.
data/CHANGELOG CHANGED
@@ -1,3 +1,5 @@
1
+ 1.3
2
+ * Add simple monitor
1
3
  1.2
2
4
  * Added Array#fixed_flatten for pre 1.9 versions
3
5
  * Remove IO.binread from CodeReloader for pre 1.9 versions
@@ -5,6 +5,7 @@ module Splib
5
5
  :Conversions,
6
6
  :Exec,
7
7
  :HumanIdealRandomIterator,
8
+ :Monitor,
8
9
  :PriorityQueue,
9
10
  :UrlShorteners
10
11
  ]
@@ -0,0 +1,86 @@
1
+ require 'thread'
2
+
3
+ module Splib
4
+
5
+ class Monitor
6
+ def initialize
7
+ @threads = []
8
+ @locks = []
9
+ @lock_owner = nil
10
+ end
11
+ # timeout:: Wait for given amount of time
12
+ # Park a thread here
13
+ def wait(timeout=nil)
14
+ @threads << Thread.current
15
+ Thread.stop
16
+ true
17
+ end
18
+ # Park thread while block is true
19
+ def wait_while
20
+ while yield
21
+ wait
22
+ end
23
+ end
24
+ # Park thread until block is true
25
+ def wait_until
26
+ until yield
27
+ wait
28
+ end
29
+ end
30
+ # Wake up earliest thread
31
+ def signal
32
+ lock
33
+ t = @threads.shift
34
+ t.wakeup if t.alive?
35
+ unlock
36
+ end
37
+ # Wake up all threads
38
+ def broadcast
39
+ lock
40
+ @threads.each do |t|
41
+ t.wakeup if t.alive?
42
+ end
43
+ @threads.clear
44
+ unlock
45
+ end
46
+ # Number of threads waiting
47
+ def waiters
48
+ @threads.size
49
+ end
50
+ # Lock the monitor
51
+ def lock
52
+ stop = false
53
+ Thread.exclusive do
54
+ unless(@locks.empty?)
55
+ @locks << Thread.current
56
+ stop = true
57
+ else
58
+ @lock_owner = Thread.current
59
+ end
60
+ end
61
+ Thread.stop if stop
62
+ end
63
+ # Unlock the monitor
64
+ def unlock
65
+ unless(@lock_owner == Thread.current)
66
+ raise ThreadError.new("Not owner attepmting to unlock monitor")
67
+ else
68
+ Thread.exclusive do
69
+ unless(@locks.empty?)
70
+ @locks.delete{|t|!t.alive?}
71
+ @lock_owner = @locks.shift
72
+ @lock_owner.wakeup
73
+ else
74
+ @lock_owner = nil
75
+ end
76
+ end
77
+ end
78
+ end
79
+ # Lock the monitor, execute block and unlock the monitor
80
+ def synchronize
81
+ lock
82
+ yield
83
+ unlock
84
+ end
85
+ end
86
+ end
@@ -2,7 +2,7 @@ spec = Gem::Specification.new do |s|
2
2
  s.name = 'splib'
3
3
  s.author = 'spox'
4
4
  s.email = 'spox@modspox.com'
5
- s.version = '1.2'
5
+ s.version = '1.3'
6
6
  s.summary = 'Spox Library'
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.files = Dir['**/*']
@@ -0,0 +1,132 @@
1
+ require 'splib'
2
+ require 'test/unit'
3
+
4
+ class MonitorTest < Test::Unit::TestCase
5
+ def setup
6
+ Splib.load :Monitor
7
+ @monitor = Splib::Monitor.new
8
+ end
9
+
10
+ def test_wait
11
+ t = []
12
+ 5.times{ t << Thread.new{ @monitor.wait } }
13
+ sleep(0.01) # give threads a chance to wait
14
+ t.each do |thread|
15
+ assert(thread.alive?)
16
+ assert(thread.stop?)
17
+ end
18
+ end
19
+
20
+ def test_signal
21
+ output = []
22
+ t = []
23
+ 5.times{ t << Thread.new{ @monitor.wait; output << 1 } }
24
+ sleep(0.01)
25
+ t.each do |thread|
26
+ assert(thread.alive?)
27
+ assert(thread.stop?)
28
+ end
29
+ assert(output.empty?)
30
+ @monitor.signal
31
+ sleep(0.01)
32
+ assert_equal(4, t.select{|th|th.alive?}.size)
33
+ assert_equal(1, output.size)
34
+ assert_equal(1, output.pop)
35
+ end
36
+
37
+ def test_broadcast
38
+ output = []
39
+ t = []
40
+ 5.times{ t << Thread.new{ @monitor.wait; output << 1 } }
41
+ sleep(0.01)
42
+ t.each do |thread|
43
+ assert(thread.alive?)
44
+ assert(thread.stop?)
45
+ end
46
+ assert(output.empty?)
47
+ @monitor.broadcast
48
+ sleep(0.01)
49
+ assert_equal(5, output.size)
50
+ 5.times{ assert_equal(1, output.pop) }
51
+ assert_equal(5, t.select{|th|!th.alive?}.size)
52
+ end
53
+
54
+ def test_wait_while
55
+ stop = true
56
+ t = Thread.new{ @monitor.wait_while{ stop } }
57
+ sleep(0.01)
58
+ assert(t.alive?)
59
+ assert(t.stop?)
60
+ @monitor.signal
61
+ sleep(0.01)
62
+ assert(t.alive?)
63
+ assert(t.stop?)
64
+ @monitor.broadcast
65
+ sleep(0.01)
66
+ assert(t.alive?)
67
+ assert(t.stop?)
68
+ stop = false
69
+ @monitor.signal
70
+ sleep(0.01)
71
+ assert(!t.alive?)
72
+ assert(t.stop?)
73
+ end
74
+
75
+ def test_wait_until
76
+ stop = false
77
+ t = Thread.new{ @monitor.wait_until{ stop } }
78
+ sleep(0.01)
79
+ assert(t.alive?)
80
+ assert(t.stop?)
81
+ @monitor.signal
82
+ sleep(0.01)
83
+ assert(t.alive?)
84
+ assert(t.stop?)
85
+ @monitor.broadcast
86
+ sleep(0.01)
87
+ assert(t.alive?)
88
+ assert(t.stop?)
89
+ stop = true
90
+ @monitor.signal
91
+ sleep(0.01)
92
+ assert(!t.alive?)
93
+ assert(t.stop?)
94
+ end
95
+
96
+ def test_waiters
97
+ t = []
98
+ (rand(20)+1).times{ t << Thread.new{ @monitor.wait } }
99
+ sleep(0.01)
100
+ assert_equal(t.size, @monitor.waiters)
101
+ @monitor.broadcast
102
+ sleep(0.01)
103
+ assert_equal(0, @monitor.waiters)
104
+ end
105
+
106
+ def test_lock_unlock
107
+ t = []
108
+ output = []
109
+ 5.times{|i| t << Thread.new{ @monitor.lock; sleep((i+1)/100.0); output << i; @monitor.unlock;}}
110
+ sleep(0.011)
111
+ assert_equal(5, t.size)
112
+ assert_equal(0, output.pop)
113
+ sleep(0.011)
114
+ assert_equal(1, output.pop)
115
+ sleep(0.011)
116
+ assert_equal(2, output.pop)
117
+ sleep(0.011)
118
+ assert_equal(3, output.pop)
119
+ sleep(0.011)
120
+ assert_equal(4, output.pop)
121
+ end
122
+
123
+ def synchronize
124
+ t = []
125
+ output = []
126
+ 5.times{|i| t << Thread.new{ @monitor.lock; sleep(i/100.0); output << i; @monitor.unlock;}}
127
+ @monitor.synchronize{ output << :done }
128
+ sleep(0.5)
129
+ assert_equal(6, output.size)
130
+ end
131
+
132
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splib
3
3
  version: !ruby/object:Gem::Version
4
- version: "1.2"
4
+ version: "1.3"
5
5
  platform: ruby
6
6
  authors:
7
7
  - spox
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-10 00:00:00 -08:00
12
+ date: 2010-01-12 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -23,6 +23,8 @@ extra_rdoc_files:
23
23
  - README.rdoc
24
24
  - CHANGELOG
25
25
  files:
26
+ - tests
27
+ - tests/cases
26
28
  - tests/cases/Array.rb
27
29
  - tests/cases/PriorityQueue.rb
28
30
  - tests/cases/UrlShorteners.rb
@@ -30,11 +32,14 @@ files:
30
32
  - tests/cases/Constants.rb
31
33
  - tests/cases/CodeReloader.rb
32
34
  - tests/cases/HumanIdealRandomIterator.rb
35
+ - tests/cases/Monitor.rb
33
36
  - tests/cases/Conversions.rb
34
37
  - tests/run_tests.rb
35
38
  - tests/samplecode2.rb
36
39
  - tests/samplecode1.rb
40
+ - lib
37
41
  - lib/splib.rb
42
+ - lib/splib
38
43
  - lib/splib/Array.rb
39
44
  - lib/splib/PriorityQueue.rb
40
45
  - lib/splib/UrlShorteners.rb
@@ -42,15 +47,14 @@ files:
42
47
  - lib/splib/Constants.rb
43
48
  - lib/splib/CodeReloader.rb
44
49
  - lib/splib/HumanIdealRandomIterator.rb
50
+ - lib/splib/Monitor.rb
45
51
  - lib/splib/Conversions.rb
46
52
  - CHANGELOG
47
53
  - LICENSE
48
54
  - splib.gemspec
49
55
  - README.rdoc
50
- has_rdoc: true
56
+ has_rdoc: false
51
57
  homepage: http://github.com/spox/splib
52
- licenses: []
53
-
54
58
  post_install_message:
55
59
  rdoc_options:
56
60
  - --title
@@ -75,9 +79,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
79
  requirements: []
76
80
 
77
81
  rubyforge_project:
78
- rubygems_version: 1.3.5
82
+ rubygems_version: 1.3.1
79
83
  signing_key:
80
- specification_version: 3
84
+ specification_version: 2
81
85
  summary: Spox Library
82
86
  test_files: []
83
87