corrade-vassal – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 1 | /* |
2 | * CVS identifier: |
||
3 | * |
||
4 | * $Id: ThreadPool.java,v 1.9 2002/05/22 15:00:55 grosbois Exp $ |
||
5 | * |
||
6 | * Class: ThreadPool |
||
7 | * |
||
8 | * Description: A pool of threads |
||
9 | * |
||
10 | * |
||
11 | * |
||
12 | * COPYRIGHT: |
||
13 | * |
||
14 | * This software module was originally developed by Raphaël Grosbois and |
||
15 | * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel |
||
16 | * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David |
||
17 | * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research |
||
18 | * Centre France S.A) in the course of development of the JPEG2000 |
||
19 | * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This |
||
20 | * software module is an implementation of a part of the JPEG 2000 |
||
21 | * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio |
||
22 | * Systems AB and Canon Research Centre France S.A (collectively JJ2000 |
||
23 | * Partners) agree not to assert against ISO/IEC and users of the JPEG |
||
24 | * 2000 Standard (Users) any of their rights under the copyright, not |
||
25 | * including other intellectual property rights, for this software module |
||
26 | * with respect to the usage by ISO/IEC and Users of this software module |
||
27 | * or modifications thereof for use in hardware or software products |
||
28 | * claiming conformance to the JPEG 2000 Standard. Those intending to use |
||
29 | * this software module in hardware or software products are advised that |
||
30 | * their use may infringe existing patents. The original developers of |
||
31 | * this software module, JJ2000 Partners and ISO/IEC assume no liability |
||
32 | * for use of this software module or modifications thereof. No license |
||
33 | * or right to this software module is granted for non JPEG 2000 Standard |
||
34 | * conforming products. JJ2000 Partners have full right to use this |
||
35 | * software module for his/her own purpose, assign or donate this |
||
36 | * software module to any third party and to inhibit third parties from |
||
37 | * using this software module for non JPEG 2000 Standard conforming |
||
38 | * products. This copyright notice must be included in all copies or |
||
39 | * derivative works of this software module. |
||
40 | * |
||
41 | * Copyright (c) 1999/2000 JJ2000 Partners. |
||
42 | * */ |
||
43 | using System; |
||
44 | namespace CSJ2K.j2k.util |
||
45 | { |
||
46 | |||
47 | /// <summary> This class implements a thread pool. The thread pool contains a set of |
||
48 | /// threads which can be given work to do. |
||
49 | /// |
||
50 | /// <P>If the Java Virtual Machine (JVM) uses native threads, then the |
||
51 | /// different threads will be able to execute in different processors in |
||
52 | /// parallel on multiprocessors machines. However, under some JVMs and |
||
53 | /// operating systems using native threads is not sufficient to allow the JVM |
||
54 | /// access to multiple processors. This is the case when native threads are |
||
55 | /// implemented using POSIX threads on lightweight processes |
||
56 | /// (i.e. PTHREAD_SCOPE_PROCESS sopce scheduling), which is the case on most |
||
57 | /// UNIX operating systems. In order to do provide access to multiple |
||
58 | /// processors it is necessary to set the concurrency level to the number of |
||
59 | /// processors or slightly higher. This can be achieved by setting the Java |
||
60 | /// system property with the name defined by CONCURRENCY_PROP_NAME to some |
||
61 | /// non-negative number. This will make use of the 'NativeServices' class and |
||
62 | /// supporting native libraries. See 'NativeServices' for details. See |
||
63 | /// 'CONCURRENCY_PROP_NAME' for the name of the property. |
||
64 | /// |
||
65 | /// <P>Initially the thread pool contains a user specified number of idle |
||
66 | /// threads. Idle threads can be given a target which is run. While running the |
||
67 | /// target the thread temporarily leaves the idle list. When the target |
||
68 | /// finishes, it joins the idle list again, waiting for a new target. When a |
||
69 | /// target is finished a thread can be notified on a particular object that is |
||
70 | /// given as a lock. |
||
71 | /// |
||
72 | /// <P>Jobs can be submitted using Runnable interfaces, using the 'runTarget()' |
||
73 | /// methods. When the job is submitted, an idle thread will be obtained, the |
||
74 | /// 'run()' method of the 'Runnable' interface will be executed and when it |
||
75 | /// completes the thread will be returned to the idle list. In general the |
||
76 | /// 'run()' method should complete in a rather short time, so that the threds |
||
77 | /// of the pool are not starved. |
||
78 | /// |
||
79 | /// <P>If using the non-asynchronous calls to 'runTarget()', it is important |
||
80 | /// that any target's 'run()' method, or any method called from it, does not |
||
81 | /// use non-asynchronous calls to 'runTarget()' on the same thread pool where |
||
82 | /// it was started. Otherwise this could create a dead-lock when there are not |
||
83 | /// enough idle threads. |
||
84 | /// |
||
85 | /// <P>The pool also has a global error and runtime exception condition (one |
||
86 | /// for 'Error' and one for 'RuntimeException'). If a target's 'run()' method |
||
87 | /// throws an 'Error' or 'RuntimeException' the corresponding exception |
||
88 | /// condition is set and the exception object saved. In any subsequent call to |
||
89 | /// 'checkTargetErrors()' the saved exception object is thrown. Likewise, if a |
||
90 | /// target's 'run()' method throws any other subclass of 'Throwable' a new |
||
91 | /// 'RuntimeException' is created and saved. It will be thrown on a subsequent |
||
92 | /// call to 'checkTargetErrors()'. If more than one exception occurs between |
||
93 | /// calls to 'checkTargetErrors()' only the last one is saved. Any 'Error' |
||
94 | /// condition has precedence on all 'RuntimeException' conditions. The threads |
||
95 | /// in the pool are unaffected by any exceptions thrown by targets. |
||
96 | /// |
||
97 | /// <P>The only exception to the above is the 'ThreadDeath' exception. If a |
||
98 | /// target's 'run()' method throws the 'ThreadDeath' exception a warning |
||
99 | /// message is printed and the exception is propagated, which will terminate |
||
100 | /// the thread in which it occurs. This could lead to instabilities of the |
||
101 | /// pool. The 'ThreadDeath' exception should never be thrown by the program. It |
||
102 | /// is thrown by the Java(TM) Virtual Machine when Thread.stop() is |
||
103 | /// called. This method is deprecated and should never be called. |
||
104 | /// |
||
105 | /// <P>All the threads in the pool are "daemon" threads and will automatically |
||
106 | /// terminate when no daemon threads are running. |
||
107 | /// |
||
108 | /// </summary> |
||
109 | /// <seealso cref="NativeServices"> |
||
110 | /// |
||
111 | /// </seealso> |
||
112 | /// <seealso cref="CONCURRENCY_PROP_NAME"> |
||
113 | /// |
||
114 | /// </seealso> |
||
115 | /// <seealso cref="Runnable"> |
||
116 | /// |
||
117 | /// </seealso> |
||
118 | /// <seealso cref="Thread"> |
||
119 | /// |
||
120 | /// </seealso> |
||
121 | /// <seealso cref="Error"> |
||
122 | /// |
||
123 | /// </seealso> |
||
124 | /// <seealso cref="RuntimeException"> |
||
125 | /// |
||
126 | /// |
||
127 | /// </seealso> |
||
128 | public class ThreadPool |
||
129 | { |
||
130 | /// <summary> Returns the size of the pool. That is the number of threads in this |
||
131 | /// pool (idle + busy). |
||
132 | /// |
||
133 | /// </summary> |
||
134 | /// <returns> The pool's size. |
||
135 | /// |
||
136 | /// |
||
137 | /// </returns> |
||
138 | virtual public int Size |
||
139 | { |
||
140 | get |
||
141 | { |
||
142 | return idle.Length; |
||
143 | } |
||
144 | |||
145 | } |
||
146 | |||
147 | /// <summary>The name of the property that sets the concurrency level: |
||
148 | /// jj2000.j2k.util.ThreadPool.concurrency |
||
149 | /// </summary> |
||
150 | public const System.String CONCURRENCY_PROP_NAME = "jj2000.j2k.util.ThreadPool.concurrency"; |
||
151 | |||
152 | /// <summary>The array of idle threads and the lock for the manipulation of the |
||
153 | /// idle thread list. |
||
154 | /// </summary> |
||
155 | private ThreadPoolThread[] idle; |
||
156 | |||
157 | /// <summary>The number of idle threads </summary> |
||
158 | private int nidle; |
||
159 | |||
160 | /// <summary>The name of the pool </summary> |
||
161 | private System.String poolName; |
||
162 | |||
163 | /// <summary>The priority for the pool </summary> |
||
164 | private int poolPriority; |
||
165 | |||
166 | /// <summary>The last error thrown by a target. Null if none </summary> |
||
167 | // NOTE: needs to be volatile, so that only one copy exits in memory |
||
168 | private volatile System.ApplicationException targetE; |
||
169 | |||
170 | /// <summary>The last runtime exception thrown by a target. Null if none </summary> |
||
171 | // NOTE: needs to be volatile, so that only one copy exits in memory |
||
172 | private volatile System.SystemException targetRE; |
||
173 | |||
174 | //UPGRADE_NOTE: Field 'EnclosingInstance' was added to class 'ThreadPoolThread' to access its enclosing instance. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1019'" |
||
175 | /// <summary> The threads that are managed by the pool. |
||
176 | /// |
||
177 | /// </summary> |
||
178 | internal class ThreadPoolThread:SupportClass.ThreadClass |
||
179 | { |
||
180 | private void InitBlock(ThreadPool enclosingInstance) |
||
181 | { |
||
182 | this.enclosingInstance = enclosingInstance; |
||
183 | } |
||
184 | private ThreadPool enclosingInstance; |
||
185 | public ThreadPool Enclosing_Instance |
||
186 | { |
||
187 | get |
||
188 | { |
||
189 | return enclosingInstance; |
||
190 | } |
||
191 | |||
192 | } |
||
193 | private IThreadRunnable target; |
||
194 | private System.Object lock_Renamed; |
||
195 | private bool doNotifyAll; |
||
196 | |||
197 | /// <summary> Creates a ThreadPoolThread object, setting its name according to |
||
198 | /// the given 'idx', daemon type and the priority to the one of the |
||
199 | /// pool. |
||
200 | /// |
||
201 | /// </summary> |
||
202 | /// <param name="idx">The index of this thread in the pool |
||
203 | /// |
||
204 | /// </param> |
||
205 | /// <param name="name">The name of the thread |
||
206 | /// |
||
207 | /// </param> |
||
208 | public ThreadPoolThread(ThreadPool enclosingInstance, int idx, System.String name):base(name) |
||
209 | { |
||
210 | InitBlock(enclosingInstance); |
||
211 | IsBackground = true; |
||
212 | //UPGRADE_TODO: The differences in the type of parameters for method 'java.lang.Thread.setPriority' may cause compilation errors. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'" |
||
213 | Priority = (System.Threading.ThreadPriority) Enclosing_Instance.poolPriority; |
||
214 | } |
||
215 | |||
216 | /// <summary> The method that is run by the thread. This method first joins the |
||
217 | /// idle state in the pool and then enters an infinite loop. In this |
||
218 | /// loop it waits until a target to run exists and runs it. Once the |
||
219 | /// target's run() method is done it re-joins the idle state and |
||
220 | /// notifies the waiting lock object, if one exists. |
||
221 | /// |
||
222 | /// <P>An interrupt on this thread has no effect other than forcing a |
||
223 | /// check on the target. Normally the target is checked every time the |
||
224 | /// thread is woken up by notify, no interrupts should be done. |
||
225 | /// |
||
226 | /// <P>Any exception thrown by the target's 'run()' method is catched |
||
227 | /// and this thread is not affected, except for 'ThreadDeath'. If a |
||
228 | /// 'ThreadDeath' exception is catched a warning message is printed by |
||
229 | /// the 'FacilityManager' and the exception is propagated up. For |
||
230 | /// exceptions which are subclasses of 'Error' or 'RuntimeException' |
||
231 | /// the corresponding error condition is set and this thread is not |
||
232 | /// affected. For any other exceptions a new 'RuntimeException' is |
||
233 | /// created and the error condition is set, this thread is not affected. |
||
234 | /// |
||
235 | /// </summary> |
||
236 | override public void Run() |
||
237 | { |
||
238 | // Join the idle threads list |
||
239 | Enclosing_Instance.putInIdleList(this); |
||
240 | // Permanently lock the object while running so that target can |
||
241 | // not be changed until we are waiting again. While waiting for a |
||
242 | // target the lock is released. |
||
243 | lock (this) |
||
244 | { |
||
245 | while (true) |
||
246 | { |
||
247 | // Wait until we get a target |
||
248 | while (target == null) |
||
249 | { |
||
250 | try |
||
251 | { |
||
252 | System.Threading.Monitor.Wait(this); |
||
253 | } |
||
254 | catch (System.Threading.ThreadInterruptedException) |
||
255 | { |
||
256 | } |
||
257 | } |
||
258 | // Run the target and catch all possible errors |
||
259 | try |
||
260 | { |
||
261 | target.Run(); |
||
262 | } |
||
263 | //UPGRADE_NOTE: Exception 'java.lang.ThreadDeath' was converted to 'System.ApplicationException' which has different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1100'" |
||
264 | catch (System.Threading.ThreadAbortException td) |
||
265 | { |
||
266 | // We have been instructed to abruptly terminate |
||
267 | // the thread, which should never be done. This can |
||
268 | // cause another thread, or the system, to lock. |
||
269 | FacilityManager.getMsgLogger().printmsg(CSJ2K.j2k.util.MsgLogger_Fields.WARNING, "Thread.stop() called on a ThreadPool " + "thread or ThreadDeath thrown. This is " + "deprecated. Lock-up might occur."); |
||
270 | throw td; |
||
271 | } |
||
272 | catch (System.ApplicationException e) |
||
273 | { |
||
274 | Enclosing_Instance.targetE = e; |
||
275 | } |
||
276 | catch (System.SystemException re) |
||
277 | { |
||
278 | Enclosing_Instance.targetRE = re; |
||
279 | } |
||
280 | //UPGRADE_NOTE: Exception 'java.lang.Throwable' was converted to 'System.Exception' which has different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1100'" |
||
281 | catch (System.Exception) |
||
282 | { |
||
283 | // A totally unexpected error has occurred |
||
284 | // (Thread.stop(Throwable) has been used, which should |
||
285 | // never be. |
||
286 | Enclosing_Instance.targetRE = new System.SystemException("Unchecked exception " + "thrown by target's " + "run() method in pool " + Enclosing_Instance.poolName + "."); |
||
287 | } |
||
288 | // Join idle threads |
||
289 | Enclosing_Instance.putInIdleList(this); |
||
290 | // Release the target and notify lock (i.e. wakeup) |
||
291 | target = null; |
||
292 | if (lock_Renamed != null) |
||
293 | { |
||
294 | lock (lock_Renamed) |
||
295 | { |
||
296 | if (doNotifyAll) |
||
297 | { |
||
298 | System.Threading.Monitor.PulseAll(lock_Renamed); |
||
299 | } |
||
300 | else |
||
301 | { |
||
302 | System.Threading.Monitor.Pulse(lock_Renamed); |
||
303 | } |
||
304 | } |
||
305 | } |
||
306 | } |
||
307 | } |
||
308 | } |
||
309 | |||
310 | /// <summary> Assigns a target to this thread, with an optional notify lock and a |
||
311 | /// notify mode. The another target is currently running the method |
||
312 | /// will block until it terminates. After setting the new target the |
||
313 | /// runner thread will be wakenup and execytion will start. |
||
314 | /// |
||
315 | /// </summary> |
||
316 | /// <param name="target">The runnable object containing the 'run()' method to |
||
317 | /// run. |
||
318 | /// |
||
319 | /// </param> |
||
320 | /// <param name="lock">An object on which notify will be called once the |
||
321 | /// target's run method has finished. A thread to be notified should be |
||
322 | /// waiting on that object. If null no thread is notified. |
||
323 | /// |
||
324 | /// </param> |
||
325 | /// <param name="notifyAll">If true 'notifyAll()', instead of 'notify()', will |
||
326 | /// be called on tghe lock. |
||
327 | /// |
||
328 | /// </param> |
||
329 | //UPGRADE_NOTE: Synchronized keyword was removed from method 'setTarget'. Lock expression was added. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1027'" |
||
330 | internal virtual void setTarget(IThreadRunnable target, System.Object lock_Renamed, bool notifyAll) |
||
331 | { |
||
332 | lock (this) |
||
333 | { |
||
334 | // Set the target |
||
335 | this.target = target; |
||
336 | this.lock_Renamed = lock_Renamed; |
||
337 | doNotifyAll = notifyAll; |
||
338 | // Wakeup the thread |
||
339 | System.Threading.Monitor.Pulse(this); |
||
340 | } |
||
341 | } |
||
342 | } |
||
343 | |||
344 | /// <summary> Creates a new thread pool of the given size, thread priority and pool |
||
345 | /// name. |
||
346 | /// |
||
347 | /// <P>If the Java system property of the name defined by |
||
348 | /// 'CONCURRENCY_PROP_NAME' is set, then an attempt will be made to load |
||
349 | /// the library that supports concurrency setting (see |
||
350 | /// 'NativeServices'). If that succeds the concurrency level will be set to |
||
351 | /// the specified value. Otherwise a warning is printed. |
||
352 | /// |
||
353 | /// </summary> |
||
354 | /// <param name="size">The size of the pool (number of threads to create in the |
||
355 | /// pool). |
||
356 | /// |
||
357 | /// </param> |
||
358 | /// <param name="priority">The priority to give to the threads in the pool. If |
||
359 | /// less than 'Thread.MIN_PRIORITY' it will be the same as the priority of |
||
360 | /// the calling thread. |
||
361 | /// |
||
362 | /// </param> |
||
363 | /// <param name="name">The name of the pool. If null a default generic name is |
||
364 | /// chosen. |
||
365 | /// |
||
366 | /// </param> |
||
367 | /// <seealso cref="NativeServices"> |
||
368 | /// |
||
369 | /// </seealso> |
||
370 | /// <seealso cref="CONCURRENCY_PROP_NAME"> |
||
371 | /// |
||
372 | /// </seealso> |
||
373 | public ThreadPool(int size, int priority, System.String name) |
||
374 | { |
||
375 | int i; |
||
376 | ThreadPoolThread t; |
||
377 | //System.String prop; |
||
378 | //int clevel; |
||
379 | |||
380 | // Initialize variables checking for special cases |
||
381 | if (size <= 0) |
||
382 | { |
||
383 | throw new System.ArgumentException("Pool must be of positive size"); |
||
384 | } |
||
385 | if (priority < (int) System.Threading.ThreadPriority.Lowest) |
||
386 | { |
||
387 | poolPriority = (System.Int32) SupportClass.ThreadClass.Current().Priority; |
||
388 | } |
||
389 | else |
||
390 | { |
||
391 | poolPriority = (priority < (int) System.Threading.ThreadPriority.Highest)?priority:(int) System.Threading.ThreadPriority.Highest; |
||
392 | } |
||
393 | if (name == null) |
||
394 | { |
||
395 | poolName = "Anonymous ThreadPool"; |
||
396 | } |
||
397 | else |
||
398 | { |
||
399 | poolName = name; |
||
400 | } |
||
401 | |||
402 | // Allocate internal variables |
||
403 | idle = new ThreadPoolThread[size]; |
||
404 | nidle = 0; |
||
405 | |||
406 | // Create and start the threads |
||
407 | for (i = 0; i < size; i++) |
||
408 | { |
||
409 | t = new ThreadPoolThread(this, i, poolName + "-" + i); |
||
410 | t.Start(); |
||
411 | } |
||
412 | } |
||
413 | |||
414 | /// <summary> Runs the run method of the specified target in an idle thread of this |
||
415 | /// pool. When the target's run method completes, the thread waiting on the |
||
416 | /// lock object is notified, if any. If there is currently no idle thread |
||
417 | /// the method will block until a thread of the pool becomes idle or the |
||
418 | /// calling thread is interrupted. |
||
419 | /// |
||
420 | /// <P>This method is the same as <tt>runTarget(t,l,true,false)</tt>. |
||
421 | /// |
||
422 | /// </summary> |
||
423 | /// <param name="t">The target. The 'run()' method of this object will be run in |
||
424 | /// an idle thread of the pool. |
||
425 | /// |
||
426 | /// </param> |
||
427 | /// <param name="l">The lock object. A thread waiting on the lock of the 'l' |
||
428 | /// object will be notified, through the 'notify()' call, when the target's |
||
429 | /// run method completes. If null no thread is notified. |
||
430 | /// |
||
431 | /// </param> |
||
432 | /// <returns> True if the target was submitted to some thread. False if no |
||
433 | /// idle thread could be found and the target was not submitted for |
||
434 | /// execution. |
||
435 | /// |
||
436 | /// |
||
437 | /// </returns> |
||
438 | public virtual bool runTarget(IThreadRunnable t, System.Object l) |
||
439 | { |
||
440 | return runTarget(t, l, false, false); |
||
441 | } |
||
442 | |||
443 | /// <summary> Runs the run method of the specified target in an idle thread of this |
||
444 | /// pool. When the target's run method completes, the thread waiting on the |
||
445 | /// lock object is notified, if any. If there is currently no idle thread |
||
446 | /// and the asynchronous mode is not used the method will block until a |
||
447 | /// thread of the pool becomes idle or the calling thread is |
||
448 | /// interrupted. If the asynchronous mode is used then the method will not |
||
449 | /// block and will return false. |
||
450 | /// |
||
451 | /// <P>This method is the same as <tt>runTarget(t,l,async,false)</tt>. |
||
452 | /// |
||
453 | /// </summary> |
||
454 | /// <param name="t">The target. The 'run()' method of this object will be run in |
||
455 | /// an idle thread of the pool. |
||
456 | /// |
||
457 | /// </param> |
||
458 | /// <param name="l">The lock object. A thread waiting on the lock of the 'l' |
||
459 | /// object will be notified, through the 'notify()' call, when the target's |
||
460 | /// run method completes. If null no thread is notified. |
||
461 | /// |
||
462 | /// </param> |
||
463 | /// <param name="async">If true the asynchronous mode will be used. |
||
464 | /// |
||
465 | /// </param> |
||
466 | /// <returns> True if the target was submitted to some thread. False if no |
||
467 | /// idle thread could be found and the target was not submitted for |
||
468 | /// execution. |
||
469 | /// |
||
470 | /// |
||
471 | /// </returns> |
||
472 | public virtual bool runTarget(IThreadRunnable t, System.Object l, bool async) |
||
473 | { |
||
474 | return runTarget(t, l, async, false); |
||
475 | } |
||
476 | |||
477 | /// <summary> Runs the run method of the specified target in an idle thread of this |
||
478 | /// pool. When the target's run method completes, the thread waiting on the |
||
479 | /// lock object is notified, if any. If there is currently no idle thread |
||
480 | /// and the asynchronous mode is not used the method will block until a |
||
481 | /// thread of the pool becomes idle or the calling thread is |
||
482 | /// interrupted. If the asynchronous mode is used then the method will not |
||
483 | /// block and will return false. |
||
484 | /// |
||
485 | /// </summary> |
||
486 | /// <param name="t">The target. The 'run()' method of this object will be run in |
||
487 | /// an idle thread of the pool. |
||
488 | /// |
||
489 | /// </param> |
||
490 | /// <param name="l">The lock object. A thread waiting on the lock of the 'l' |
||
491 | /// object will be notified, through the 'notify()' call, when the target's |
||
492 | /// run method completes. If null no thread is notified. |
||
493 | /// |
||
494 | /// </param> |
||
495 | /// <param name="async">If true the asynchronous mode will be used. |
||
496 | /// |
||
497 | /// </param> |
||
498 | /// <param name="notifyAll">If true, threads waiting on the lock of the 'l' object |
||
499 | /// will be notified trough the 'notifyAll()' instead of the normal |
||
500 | /// 'notify()' call. This is not normally needed. |
||
501 | /// |
||
502 | /// </param> |
||
503 | /// <returns> True if the target was submitted to some thread. False if no |
||
504 | /// idle thread could be found and the target was not submitted for |
||
505 | /// execution. |
||
506 | /// |
||
507 | /// |
||
508 | /// </returns> |
||
509 | public virtual bool runTarget(IThreadRunnable t, System.Object l, bool async, bool notifyAll) |
||
510 | { |
||
511 | ThreadPoolThread runner; // The thread to run the target |
||
512 | |||
513 | // Get a thread to run |
||
514 | runner = getIdle(async); |
||
515 | // If no runner return failure |
||
516 | if (runner == null) |
||
517 | return false; |
||
518 | // Set the runner |
||
519 | runner.setTarget(t, l, notifyAll); |
||
520 | return true; |
||
521 | } |
||
522 | |||
523 | /// <summary> Checks that no error or runtime exception in any target have occurred |
||
524 | /// so far. If an error or runtime exception has occurred in a target's run |
||
525 | /// method they are thrown by this method. |
||
526 | /// |
||
527 | /// </summary> |
||
528 | /// <exception cref="Error">If an error condition has been thrown by a target |
||
529 | /// 'run()' method. |
||
530 | /// |
||
531 | /// </exception> |
||
532 | /// <exception cref="RuntimeException">If a runtime exception has been thrown by a |
||
533 | /// target 'run()' method. |
||
534 | /// |
||
535 | /// </exception> |
||
536 | public virtual void checkTargetErrors() |
||
537 | { |
||
538 | // Check for Error |
||
539 | if (targetE != null) |
||
540 | throw targetE; |
||
541 | // Check for RuntimeException |
||
542 | if (targetRE != null) |
||
543 | throw targetRE; |
||
544 | } |
||
545 | |||
546 | /// <summary> Clears the current target error conditions, if any. Note that a thread |
||
547 | /// in the pool might have set the error conditions since the last check |
||
548 | /// and that those error conditions will be lost. Likewise, before |
||
549 | /// returning from this method another thread might set the error |
||
550 | /// conditions. There is no guarantee that no error conditions exist when |
||
551 | /// returning from this method. |
||
552 | /// |
||
553 | /// <P>In order to ensure that no error conditions exist when returning |
||
554 | /// from this method cooperation from the targets and the thread using this |
||
555 | /// pool is necessary (i.e. currently no targets running or waiting to |
||
556 | /// run). |
||
557 | /// |
||
558 | /// </summary> |
||
559 | public virtual void clearTargetErrors() |
||
560 | { |
||
561 | // Clear the error and runtime exception conditions |
||
562 | targetE = null; |
||
563 | targetRE = null; |
||
564 | } |
||
565 | |||
566 | /// <summary> Puts the thread 't' in the idle list. The thread 't' should be in fact |
||
567 | /// idle and ready to accept a new target when it joins the idle list. |
||
568 | /// |
||
569 | /// <P> An idle thread that is already in the list should never add itself |
||
570 | /// to the list before it is removed. For efficiency reasons there is no |
||
571 | /// check to see if the thread is already in the list of idle threads. |
||
572 | /// |
||
573 | /// <P> If the idle list was empty 'notify()' will be called on the 'idle' |
||
574 | /// array, to wake up a thread that might be waiting (within the |
||
575 | /// 'getIdle()' method) on an idle thread to become available. |
||
576 | /// |
||
577 | /// </summary> |
||
578 | /// <param name="t">The thread to put in the idle list. |
||
579 | /// |
||
580 | /// </param> |
||
581 | private void putInIdleList(ThreadPoolThread t) |
||
582 | { |
||
583 | // NOTE: if already in idle => catastrophe! (should be OK since // |
||
584 | // this is private method) |
||
585 | // Lock the idle array to avoid races with 'getIdle()' |
||
586 | lock (idle) |
||
587 | { |
||
588 | idle[nidle] = t; |
||
589 | nidle++; |
||
590 | // If idle array was empty wakeup any waiting threads. |
||
591 | if (nidle == 1) |
||
592 | System.Threading.Monitor.Pulse(idle); |
||
593 | } |
||
594 | } |
||
595 | |||
596 | /// <summary> Returns and idle thread and removes it from the list of idle |
||
597 | /// threads. In asynchronous mode it will immediately return an idle |
||
598 | /// thread, or null if none is available. In non-asynchronous mode it will |
||
599 | /// block until a thread of the pool becomes idle or the calling thread is |
||
600 | /// interrupted. |
||
601 | /// |
||
602 | /// <P>If in non-asynchronous mode and there are currently no idle threads |
||
603 | /// available the calling thread will wait on the 'idle' array lock, until |
||
604 | /// notified by 'putInIdleList()' that an idle thread might have become |
||
605 | /// available. |
||
606 | /// |
||
607 | /// </summary> |
||
608 | /// <param name="async">If true asynchronous mode is used. |
||
609 | /// |
||
610 | /// </param> |
||
611 | /// <returns> An idle thread of the pool, that has been removed from the idle |
||
612 | /// list, or null if none is available. |
||
613 | /// |
||
614 | /// </returns> |
||
615 | private ThreadPoolThread getIdle(bool async) |
||
616 | { |
||
617 | // Lock the idle array to avoid races with 'putInIdleList()' |
||
618 | lock (idle) |
||
619 | { |
||
620 | if (async) |
||
621 | { |
||
622 | // In asynchronous mode just return null if no idle thread |
||
623 | if (nidle == 0) |
||
624 | return null; |
||
625 | } |
||
626 | else |
||
627 | { |
||
628 | // In synchronous mode wait until a thread becomes idle |
||
629 | while (nidle == 0) |
||
630 | { |
||
631 | try |
||
632 | { |
||
633 | System.Threading.Monitor.Wait(idle); |
||
634 | } |
||
635 | catch (System.Threading.ThreadInterruptedException) |
||
636 | { |
||
637 | // If we were interrupted just return null |
||
638 | return null; |
||
639 | } |
||
640 | } |
||
641 | } |
||
642 | // Decrease the idle count and return one of the idle threads |
||
643 | nidle--; |
||
644 | return idle[nidle]; |
||
645 | } |
||
646 | } |
||
647 | } |
||
648 | } |