lib/thread.rb
DEFINITIONS
This source file includes following functions.
1 #
2 # thread.rb - thread support classes
3 # $Date: 2002/08/27 08:31:08 $
4 # by Yukihiro Matsumoto <matz@netlab.co.jp>
5 #
6 # Copyright (C) 2001 Yukihiro Matsumoto
7 # Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
8 # Copyright (C) 2000 Information-technology Promotion Agency, Japan
9 #
10
11 unless defined? Thread
12 fail "Thread not available for this ruby interpreter"
13 end
14
15 unless defined? ThreadError
16 class ThreadError<StandardError
17 end
18 end
19
20 if $DEBUG
21 Thread.abort_on_exception = true
22 end
23
24 def Thread.exclusive
25 _old = Thread.critical
26 begin
27 Thread.critical = true
28 return yield
29 ensure
30 Thread.critical = _old
31 end
32 end
33
34 class Mutex
35 def initialize
36 @waiting = []
37 @locked = false;
38 @waiting.taint # enable tainted comunication
39 self.taint
40 end
41
42 def locked?
43 @locked
44 end
45
46 def try_lock
47 result = false
48 Thread.critical = true
49 unless @locked
50 @locked = true
51 result = true
52 end
53 Thread.critical = false
54 result
55 end
56
57 def lock
58 while (Thread.critical = true; @locked)
59 @waiting.push Thread.current
60 Thread.stop
61 end
62 @locked = true
63 Thread.critical = false
64 self
65 end
66
67 def unlock
68 return unless @locked
69 Thread.critical = true
70 @locked = false
71 begin
72 t = @waiting.shift
73 t.wakeup if t
74 rescue ThreadError
75 retry
76 end
77 Thread.critical = false
78 begin
79 t.run if t
80 rescue ThreadError
81 end
82 self
83 end
84
85 def synchronize
86 lock
87 begin
88 yield
89 ensure
90 unlock
91 end
92 end
93
94 def exclusive_unlock
95 return unless @locked
96 Thread.exclusive do
97 @locked = false
98 begin
99 t = @waiting.shift
100 t.wakeup if t
101 rescue ThreadError
102 retry
103 end
104 yield
105 end
106 self
107 end
108 end
109
110 class ConditionVariable
111 def initialize
112 @waiters = []
113 end
114
115 def wait(mutex)
116 mutex.exclusive_unlock do
117 @waiters.push(Thread.current)
118 Thread.stop
119 end
120 mutex.lock
121 end
122
123 def signal
124 begin
125 t = @waiters.shift
126 t.run if t
127 rescue ThreadError
128 retry
129 end
130 end
131
132 def broadcast
133 waiters0 = nil
134 Thread.exclusive do
135 waiters0 = @waiters.dup
136 @waiters.clear
137 end
138 for t in waiters0
139 begin
140 t.run
141 rescue ThreadError
142 end
143 end
144 end
145 end
146
147 class Queue
148 def initialize
149 @que = []
150 @waiting = []
151 @que.taint # enable tainted comunication
152 @waiting.taint
153 self.taint
154 end
155
156 def push(obj)
157 Thread.critical = true
158 @que.push obj
159 begin
160 t = @waiting.shift
161 t.wakeup if t
162 rescue ThreadError
163 retry
164 ensure
165 Thread.critical = false
166 end
167 begin
168 t.run if t
169 rescue ThreadError
170 end
171 end
172 alias << push
173 alias enq push
174
175 def pop(non_block=false)
176 while (Thread.critical = true; @que.empty?)
177 raise ThreadError, "queue empty" if non_block
178 @waiting.push Thread.current
179 Thread.stop
180 end
181 @que.shift
182 ensure
183 Thread.critical = false
184 end
185 alias shift pop
186 alias deq pop
187
188 def empty?
189 @que.empty?
190 end
191
192 def clear
193 @que.clear
194 end
195
196 def length
197 @que.length
198 end
199 def size
200 length
201 end
202
203 def num_waiting
204 @waiting.size
205 end
206 end
207
208 class SizedQueue<Queue
209 def initialize(max)
210 raise ArgumentError, "queue size must be positive" unless max > 0
211 @max = max
212 @queue_wait = []
213 @queue_wait.taint # enable tainted comunication
214 super()
215 end
216
217 def max
218 @max
219 end
220
221 def max=(max)
222 Thread.critical = true
223 if max <= @max
224 @max = max
225 Thread.critical = false
226 else
227 diff = max - @max
228 @max = max
229 Thread.critical = false
230 diff.times do
231 begin
232 t = @queue_wait.shift
233 t.run if t
234 rescue ThreadError
235 retry
236 end
237 end
238 end
239 max
240 end
241
242 def push(obj)
243 Thread.critical = true
244 while @que.length >= @max
245 @queue_wait.push Thread.current
246 Thread.stop
247 Thread.critical = true
248 end
249 super
250 end
251 alias << push
252 alias enq push
253
254 def pop(*args)
255 retval = super
256 Thread.critical = true
257 if @que.length < @max
258 begin
259 t = @queue_wait.shift
260 t.wakeup if t
261 rescue ThreadError
262 retry
263 ensure
264 Thread.critical = false
265 end
266 begin
267 t.run if t
268 rescue ThreadError
269 end
270 end
271 retval
272 end
273 alias shift pop
274 alias deq pop
275
276 def num_waiting
277 @waiting.size + @queue_wait.size
278 end
279 end