PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/CSJ2K/Modules/j2k/util/ThreadPool.cs

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