splib 1.2 → 1.3

Sign up to get free protection for your applications and to get access to all the features.
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