aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ThirdParty/SmartThreadPool/SmartThreadPool.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ThirdParty/SmartThreadPool/SmartThreadPool.cs1634
1 files changed, 817 insertions, 817 deletions
diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.cs
index 297e20e..7cc7fbf 100644
--- a/ThirdParty/SmartThreadPool/SmartThreadPool.cs
+++ b/ThirdParty/SmartThreadPool/SmartThreadPool.cs
@@ -3,7 +3,7 @@
3// Smart Thread Pool 3// Smart Thread Pool
4// 7 Aug 2004 - Initial release 4// 7 Aug 2004 - Initial release
5// 5//
6// 14 Sep 2004 - Bug fixes 6// 14 Sep 2004 - Bug fixes
7// 7//
8// 15 Oct 2004 - Added new features 8// 15 Oct 2004 - Added new features
9// - Work items return result. 9// - Work items return result.
@@ -18,13 +18,13 @@
18// - Added finalizers. 18// - Added finalizers.
19// - Changed Exceptions so they are serializable. 19// - Changed Exceptions so they are serializable.
20// - Fixed the bug in one of the SmartThreadPool constructors. 20// - Fixed the bug in one of the SmartThreadPool constructors.
21// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. 21// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters.
22// The SmartThreadPool.WaitAny() is still limited by the .NET Framework. 22// The SmartThreadPool.WaitAny() is still limited by the .NET Framework.
23// - Added PostExecute with options on which cases to call it. 23// - Added PostExecute with options on which cases to call it.
24// - Added option to dispose of the state objects. 24// - Added option to dispose of the state objects.
25// - Added a WaitForIdle() method that waits until the work items queue is empty. 25// - Added a WaitForIdle() method that waits until the work items queue is empty.
26// - Added an STPStartInfo class for the initialization of the thread pool. 26// - Added an STPStartInfo class for the initialization of the thread pool.
27// - Changed exception handling so if a work item throws an exception it 27// - Changed exception handling so if a work item throws an exception it
28// is rethrown at GetResult(), rather then firing an UnhandledException event. 28// is rethrown at GetResult(), rather then firing an UnhandledException event.
29// Note that PostExecute exception are always ignored. 29// Note that PostExecute exception are always ignored.
30// 30//
@@ -32,10 +32,10 @@
32// - Fixed lost of work items bug 32// - Fixed lost of work items bug
33// 33//
34// 3 Jul 2005: Changes. 34// 3 Jul 2005: Changes.
35// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. 35// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed.
36// 36//
37// 16 Aug 2005: Changes. 37// 16 Aug 2005: Changes.
38// - Fixed bug where the InUseThreads becomes negative when canceling work items. 38// - Fixed bug where the InUseThreads becomes negative when canceling work items.
39// 39//
40// 31 Jan 2006 - Changes: 40// 31 Jan 2006 - Changes:
41// - Added work items priority 41// - Added work items priority
@@ -45,7 +45,7 @@
45// - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array 45// - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array
46// it returns true rather then throwing an exception. 46// it returns true rather then throwing an exception.
47// - Added option to start the STP and the WIG as suspended 47// - Added option to start the STP and the WIG as suspended
48// - Exception behavior changed, the real exception is returned by an 48// - Exception behavior changed, the real exception is returned by an
49// inner exception 49// inner exception
50// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) 50// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.)
51// - Added performance counters 51// - Added performance counters
@@ -54,17 +54,17 @@
54// 13 Feb 2006 - Changes: 54// 13 Feb 2006 - Changes:
55// - Added a call to the dispose of the Performance Counter so 55// - Added a call to the dispose of the Performance Counter so
56// their won't be a Performance Counter leak. 56// their won't be a Performance Counter leak.
57// - Added exception catch in case the Performance Counters cannot 57// - Added exception catch in case the Performance Counters cannot
58// be created. 58// be created.
59// 59//
60// 17 May 2008 - Changes: 60// 17 May 2008 - Changes:
61// - Changed the dispose behavior and removed the Finalizers. 61// - Changed the dispose behavior and removed the Finalizers.
62// - Enabled the change of the MaxThreads and MinThreads at run time. 62// - Enabled the change of the MaxThreads and MinThreads at run time.
63// - Enabled the change of the Concurrency of a IWorkItemsGroup at run 63// - Enabled the change of the Concurrency of a IWorkItemsGroup at run
64// time If the IWorkItemsGroup is a SmartThreadPool then the Concurrency 64// time If the IWorkItemsGroup is a SmartThreadPool then the Concurrency
65// refers to the MaxThreads. 65// refers to the MaxThreads.
66// - Improved the cancel behavior. 66// - Improved the cancel behavior.
67// - Added events for thread creation and termination. 67// - Added events for thread creation and termination.
68// - Fixed the HttpContext context capture. 68// - Fixed the HttpContext context capture.
69// - Changed internal collections so they use generic collections 69// - Changed internal collections so they use generic collections
70// - Added IsIdle flag to the SmartThreadPool and IWorkItemsGroup 70// - Added IsIdle flag to the SmartThreadPool and IWorkItemsGroup
@@ -83,7 +83,7 @@
83// 83//
84// 20 August 2012 - Changes: 84// 20 August 2012 - Changes:
85// - Added set name to threads 85// - Added set name to threads
86// - Fixed the WorkItemsQueue.Dequeue. 86// - Fixed the WorkItemsQueue.Dequeue.
87// Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... } 87// Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... }
88// - Fixed SmartThreadPool.Pipe 88// - Fixed SmartThreadPool.Pipe
89// - Added IsBackground option to threads 89// - Added IsBackground option to threads
@@ -92,7 +92,7 @@
92// 92//
93// 24 August 2012 - Changes: 93// 24 August 2012 - Changes:
94// - Enabled cancel abort after cancel. See: http://smartthreadpool.codeplex.com/discussions/345937 by alecswan 94// - Enabled cancel abort after cancel. See: http://smartthreadpool.codeplex.com/discussions/345937 by alecswan
95// - Added option to set MaxStackSize of threads 95// - Added option to set MaxStackSize of threads
96 96
97#endregion 97#endregion
98 98
@@ -108,77 +108,77 @@ using Amib.Threading.Internal;
108 108
109namespace Amib.Threading 109namespace Amib.Threading
110{ 110{
111 #region SmartThreadPool class 111 #region SmartThreadPool class
112 /// <summary> 112 /// <summary>
113 /// Smart thread pool class. 113 /// Smart thread pool class.
114 /// </summary> 114 /// </summary>
115 public partial class SmartThreadPool : WorkItemsGroupBase, IDisposable 115 public partial class SmartThreadPool : WorkItemsGroupBase, IDisposable
116 { 116 {
117 #region Public Default Constants 117 #region Public Default Constants
118 118
119 /// <summary> 119 /// <summary>
120 /// Default minimum number of threads the thread pool contains. (0) 120 /// Default minimum number of threads the thread pool contains. (0)
121 /// </summary> 121 /// </summary>
122 public const int DefaultMinWorkerThreads = 0; 122 public const int DefaultMinWorkerThreads = 0;
123 123
124 /// <summary> 124 /// <summary>
125 /// Default maximum number of threads the thread pool contains. (25) 125 /// Default maximum number of threads the thread pool contains. (25)
126 /// </summary> 126 /// </summary>
127 public const int DefaultMaxWorkerThreads = 25; 127 public const int DefaultMaxWorkerThreads = 25;
128 128
129 /// <summary> 129 /// <summary>
130 /// Default idle timeout in milliseconds. (One minute) 130 /// Default idle timeout in milliseconds. (One minute)
131 /// </summary> 131 /// </summary>
132 public const int DefaultIdleTimeout = 60*1000; // One minute 132 public const int DefaultIdleTimeout = 60*1000; // One minute
133 133
134 /// <summary> 134 /// <summary>
135 /// Indicate to copy the security context of the caller and then use it in the call. (false) 135 /// Indicate to copy the security context of the caller and then use it in the call. (false)
136 /// </summary> 136 /// </summary>
137 public const bool DefaultUseCallerCallContext = false; 137 public const bool DefaultUseCallerCallContext = false;
138 138
139 /// <summary> 139 /// <summary>
140 /// Indicate to copy the HTTP context of the caller and then use it in the call. (false) 140 /// Indicate to copy the HTTP context of the caller and then use it in the call. (false)
141 /// </summary> 141 /// </summary>
142 public const bool DefaultUseCallerHttpContext = false; 142 public const bool DefaultUseCallerHttpContext = false;
143 143
144 /// <summary> 144 /// <summary>
145 /// Indicate to dispose of the state objects if they support the IDispose interface. (false) 145 /// Indicate to dispose of the state objects if they support the IDispose interface. (false)
146 /// </summary> 146 /// </summary>
147 public const bool DefaultDisposeOfStateObjects = false; 147 public const bool DefaultDisposeOfStateObjects = false;
148 148
149 /// <summary> 149 /// <summary>
150 /// The default option to run the post execute (CallToPostExecute.Always) 150 /// The default option to run the post execute (CallToPostExecute.Always)
151 /// </summary> 151 /// </summary>
152 public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always; 152 public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always;
153 153
154 /// <summary> 154 /// <summary>
155 /// The default post execute method to run. (None) 155 /// The default post execute method to run. (None)
156 /// When null it means not to call it. 156 /// When null it means not to call it.
157 /// </summary> 157 /// </summary>
158 public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback; 158 public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback;
159 159
160 /// <summary> 160 /// <summary>
161 /// The default work item priority (WorkItemPriority.Normal) 161 /// The default work item priority (WorkItemPriority.Normal)
162 /// </summary> 162 /// </summary>
163 public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal; 163 public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal;
164 164
165 /// <summary> 165 /// <summary>
166 /// The default is to work on work items as soon as they arrive 166 /// The default is to work on work items as soon as they arrive
167 /// and not to wait for the start. (false) 167 /// and not to wait for the start. (false)
168 /// </summary> 168 /// </summary>
169 public const bool DefaultStartSuspended = false; 169 public const bool DefaultStartSuspended = false;
170 170
171 /// <summary> 171 /// <summary>
172 /// The default name to use for the performance counters instance. (null) 172 /// The default name to use for the performance counters instance. (null)
173 /// </summary> 173 /// </summary>
174 public static readonly string DefaultPerformanceCounterInstanceName; 174 public static readonly string DefaultPerformanceCounterInstanceName;
175 175
176#if !(WINDOWS_PHONE) 176#if !(WINDOWS_PHONE)
177 177
178 /// <summary> 178 /// <summary>
179 /// The default thread priority (ThreadPriority.Normal) 179 /// The default thread priority (ThreadPriority.Normal)
180 /// </summary> 180 /// </summary>
181 public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; 181 public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal;
182#endif 182#endif
183 /// <summary> 183 /// <summary>
184 /// The default thread pool name. (SmartThreadPool) 184 /// The default thread pool name. (SmartThreadPool)
@@ -203,37 +203,37 @@ namespace Amib.Threading
203 203
204#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) 204#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
205 /// <summary> 205 /// <summary>
206 /// The default apartment state of a thread in the thread pool. 206 /// The default apartment state of a thread in the thread pool.
207 /// The default is ApartmentState.Unknown which means the STP will not 207 /// The default is ApartmentState.Unknown which means the STP will not
208 /// set the apartment of the thread. It will use the .NET default. 208 /// set the apartment of the thread. It will use the .NET default.
209 /// </summary> 209 /// </summary>
210 public const ApartmentState DefaultApartmentState = ApartmentState.Unknown; 210 public const ApartmentState DefaultApartmentState = ApartmentState.Unknown;
211#endif 211#endif
212 212
213 #endregion 213 #endregion
214 214
215 #region Member Variables 215 #region Member Variables
216 216
217 /// <summary> 217 /// <summary>
218 /// Dictionary of all the threads in the thread pool. 218 /// Dictionary of all the threads in the thread pool.
219 /// </summary> 219 /// </summary>
220 private readonly SynchronizedDictionary<Thread, ThreadEntry> _workerThreads = new SynchronizedDictionary<Thread, ThreadEntry>(); 220 private readonly SynchronizedDictionary<Thread, ThreadEntry> _workerThreads = new SynchronizedDictionary<Thread, ThreadEntry>();
221 221
222 /// <summary> 222 /// <summary>
223 /// Queue of work items. 223 /// Queue of work items.
224 /// </summary> 224 /// </summary>
225 private readonly WorkItemsQueue _workItemsQueue = new WorkItemsQueue(); 225 private readonly WorkItemsQueue _workItemsQueue = new WorkItemsQueue();
226 226
227 /// <summary> 227 /// <summary>
228 /// Count the work items handled. 228 /// Count the work items handled.
229 /// Used by the performance counter. 229 /// Used by the performance counter.
230 /// </summary> 230 /// </summary>
231 private int _workItemsProcessed; 231 private int _workItemsProcessed;
232 232
233 /// <summary> 233 /// <summary>
234 /// Number of threads that currently work (not idle). 234 /// Number of threads that currently work (not idle).
235 /// </summary> 235 /// </summary>
236 private int _inUseWorkerThreads; 236 private int _inUseWorkerThreads;
237 237
238 /// <summary> 238 /// <summary>
239 /// Stores a copy of the original STPStartInfo. 239 /// Stores a copy of the original STPStartInfo.
@@ -241,51 +241,51 @@ namespace Amib.Threading
241 /// </summary> 241 /// </summary>
242 private STPStartInfo _stpStartInfo; 242 private STPStartInfo _stpStartInfo;
243 243
244 /// <summary> 244 /// <summary>
245 /// Total number of work items that are stored in the work items queue 245 /// Total number of work items that are stored in the work items queue
246 /// plus the work items that the threads in the pool are working on. 246 /// plus the work items that the threads in the pool are working on.
247 /// </summary> 247 /// </summary>
248 private int _currentWorkItemsCount; 248 private int _currentWorkItemsCount;
249 249
250 /// <summary> 250 /// <summary>
251 /// Signaled when the thread pool is idle, i.e. no thread is busy 251 /// Signaled when the thread pool is idle, i.e. no thread is busy
252 /// and the work items queue is empty 252 /// and the work items queue is empty
253 /// </summary> 253 /// </summary>
254 //private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); 254 //private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
255 private ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); 255 private ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
256 256
257 /// <summary> 257 /// <summary>
258 /// An event to signal all the threads to quit immediately. 258 /// An event to signal all the threads to quit immediately.
259 /// </summary> 259 /// </summary>
260 //private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false); 260 //private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false);
261 private ManualResetEvent _shuttingDownEvent = EventWaitHandleFactory.CreateManualResetEvent(false); 261 private ManualResetEvent _shuttingDownEvent = EventWaitHandleFactory.CreateManualResetEvent(false);
262 262
263 /// <summary> 263 /// <summary>
264 /// A flag to indicate if the Smart Thread Pool is now suspended. 264 /// A flag to indicate if the Smart Thread Pool is now suspended.
265 /// </summary> 265 /// </summary>
266 private bool _isSuspended; 266 private bool _isSuspended;
267 267
268 /// <summary> 268 /// <summary>
269 /// A flag to indicate the threads to quit. 269 /// A flag to indicate the threads to quit.
270 /// </summary> 270 /// </summary>
271 private bool _shutdown; 271 private bool _shutdown;
272 272
273 /// <summary> 273 /// <summary>
274 /// Counts the threads created in the pool. 274 /// Counts the threads created in the pool.
275 /// It is used to name the threads. 275 /// It is used to name the threads.
276 /// </summary> 276 /// </summary>
277 private int _threadCounter; 277 private int _threadCounter;
278 278
279 /// <summary> 279 /// <summary>
280 /// Indicate that the SmartThreadPool has been disposed 280 /// Indicate that the SmartThreadPool has been disposed
281 /// </summary> 281 /// </summary>
282 private bool _isDisposed; 282 private bool _isDisposed;
283 283
284 /// <summary> 284 /// <summary>
285 /// Holds all the WorkItemsGroup instaces that have at least one 285 /// Holds all the WorkItemsGroup instaces that have at least one
286 /// work item int the SmartThreadPool 286 /// work item int the SmartThreadPool
287 /// This variable is used in case of Shutdown 287 /// This variable is used in case of Shutdown
288 /// </summary> 288 /// </summary>
289 private readonly SynchronizedDictionary<IWorkItemsGroup, IWorkItemsGroup> _workItemsGroups = new SynchronizedDictionary<IWorkItemsGroup, IWorkItemsGroup>(); 289 private readonly SynchronizedDictionary<IWorkItemsGroup, IWorkItemsGroup> _workItemsGroups = new SynchronizedDictionary<IWorkItemsGroup, IWorkItemsGroup>();
290 290
291 /// <summary> 291 /// <summary>
@@ -305,7 +305,7 @@ namespace Amib.Threading
305 private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance; 305 private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance;
306 306
307 307
308#if (WINDOWS_PHONE) 308#if (WINDOWS_PHONE)
309 private static readonly Dictionary<int, ThreadEntry> _threadEntries = new Dictionary<int, ThreadEntry>(); 309 private static readonly Dictionary<int, ThreadEntry> _threadEntries = new Dictionary<int, ThreadEntry>();
310#elif (_WINDOWS_CE) 310#elif (_WINDOWS_CE)
311 private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot(); 311 private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot();
@@ -316,13 +316,13 @@ namespace Amib.Threading
316#endif 316#endif
317 317
318 /// <summary> 318 /// <summary>
319 /// An event to call after a thread is created, but before 319 /// An event to call after a thread is created, but before
320 /// it's first use. 320 /// it's first use.
321 /// </summary> 321 /// </summary>
322 private event ThreadInitializationHandler _onThreadInitialization; 322 private event ThreadInitializationHandler _onThreadInitialization;
323 323
324 /// <summary> 324 /// <summary>
325 /// An event to call when a thread is about to exit, after 325 /// An event to call when a thread is about to exit, after
326 /// it is no longer belong to the pool. 326 /// it is no longer belong to the pool.
327 /// </summary> 327 /// </summary>
328 private event ThreadTerminationHandler _onThreadTermination; 328 private event ThreadTerminationHandler _onThreadTermination;
@@ -332,7 +332,7 @@ namespace Amib.Threading
332 #region Per thread properties 332 #region Per thread properties
333 333
334 /// <summary> 334 /// <summary>
335 /// A reference to the current work item a thread from the thread pool 335 /// A reference to the current work item a thread from the thread pool
336 /// is executing. 336 /// is executing.
337 /// </summary> 337 /// </summary>
338 internal static ThreadEntry CurrentThreadEntry 338 internal static ThreadEntry CurrentThreadEntry
@@ -383,78 +383,78 @@ namespace Amib.Threading
383 #region Construction and Finalization 383 #region Construction and Finalization
384 384
385 /// <summary> 385 /// <summary>
386 /// Constructor 386 /// Constructor
387 /// </summary> 387 /// </summary>
388 public SmartThreadPool() 388 public SmartThreadPool()
389 { 389 {
390 _stpStartInfo = new STPStartInfo(); 390 _stpStartInfo = new STPStartInfo();
391 Initialize(); 391 Initialize();
392 } 392 }
393 393
394 /// <summary> 394 /// <summary>
395 /// Constructor 395 /// Constructor
396 /// </summary> 396 /// </summary>
397 /// <param name="idleTimeout">Idle timeout in milliseconds</param> 397 /// <param name="idleTimeout">Idle timeout in milliseconds</param>
398 public SmartThreadPool(int idleTimeout) 398 public SmartThreadPool(int idleTimeout)
399 { 399 {
400 _stpStartInfo = new STPStartInfo 400 _stpStartInfo = new STPStartInfo
401 { 401 {
402 IdleTimeout = idleTimeout, 402 IdleTimeout = idleTimeout,
403 }; 403 };
404 Initialize(); 404 Initialize();
405 } 405 }
406 406
407 /// <summary> 407 /// <summary>
408 /// Constructor 408 /// Constructor
409 /// </summary> 409 /// </summary>
410 /// <param name="idleTimeout">Idle timeout in milliseconds</param> 410 /// <param name="idleTimeout">Idle timeout in milliseconds</param>
411 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param> 411 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param>
412 public SmartThreadPool( 412 public SmartThreadPool(
413 int idleTimeout, 413 int idleTimeout,
414 int maxWorkerThreads) 414 int maxWorkerThreads)
415 { 415 {
416 _stpStartInfo = new STPStartInfo 416 _stpStartInfo = new STPStartInfo
417 { 417 {
418 IdleTimeout = idleTimeout, 418 IdleTimeout = idleTimeout,
419 MaxWorkerThreads = maxWorkerThreads, 419 MaxWorkerThreads = maxWorkerThreads,
420 }; 420 };
421 Initialize(); 421 Initialize();
422 } 422 }
423 423
424 /// <summary> 424 /// <summary>
425 /// Constructor 425 /// Constructor
426 /// </summary> 426 /// </summary>
427 /// <param name="idleTimeout">Idle timeout in milliseconds</param> 427 /// <param name="idleTimeout">Idle timeout in milliseconds</param>
428 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param> 428 /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param>
429 /// <param name="minWorkerThreads">Lower limit of threads in the pool</param> 429 /// <param name="minWorkerThreads">Lower limit of threads in the pool</param>
430 public SmartThreadPool( 430 public SmartThreadPool(
431 int idleTimeout, 431 int idleTimeout,
432 int maxWorkerThreads, 432 int maxWorkerThreads,
433 int minWorkerThreads) 433 int minWorkerThreads)
434 { 434 {
435 _stpStartInfo = new STPStartInfo 435 _stpStartInfo = new STPStartInfo
436 { 436 {
437 IdleTimeout = idleTimeout, 437 IdleTimeout = idleTimeout,
438 MaxWorkerThreads = maxWorkerThreads, 438 MaxWorkerThreads = maxWorkerThreads,
439 MinWorkerThreads = minWorkerThreads, 439 MinWorkerThreads = minWorkerThreads,
440 }; 440 };
441 Initialize(); 441 Initialize();
442 } 442 }
443 443
444 /// <summary> 444 /// <summary>
445 /// Constructor 445 /// Constructor
446 /// </summary> 446 /// </summary>
447 /// <param name="stpStartInfo">A SmartThreadPool configuration that overrides the default behavior</param> 447 /// <param name="stpStartInfo">A SmartThreadPool configuration that overrides the default behavior</param>
448 public SmartThreadPool(STPStartInfo stpStartInfo) 448 public SmartThreadPool(STPStartInfo stpStartInfo)
449 { 449 {
450 _stpStartInfo = new STPStartInfo(stpStartInfo); 450 _stpStartInfo = new STPStartInfo(stpStartInfo);
451 Initialize(); 451 Initialize();
452 } 452 }
453 453
454 private void Initialize() 454 private void Initialize()
455 { 455 {
456 Name = _stpStartInfo.ThreadPoolName; 456 Name = _stpStartInfo.ThreadPoolName;
457 ValidateSTPStartInfo(); 457 ValidateSTPStartInfo();
458 458
459 // _stpStartInfoRW stores a read/write copy of the STPStartInfo. 459 // _stpStartInfoRW stores a read/write copy of the STPStartInfo.
460 // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten 460 // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten
@@ -462,8 +462,8 @@ namespace Amib.Threading
462 _isSuspended = _stpStartInfo.StartSuspended; 462 _isSuspended = _stpStartInfo.StartSuspended;
463 463
464#if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE) 464#if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE)
465 if (null != _stpStartInfo.PerformanceCounterInstanceName) 465 if (null != _stpStartInfo.PerformanceCounterInstanceName)
466 { 466 {
467 throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters"); 467 throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters");
468 } 468 }
469#else 469#else
@@ -486,110 +486,110 @@ namespace Amib.Threading
486 _localPCs = new LocalSTPInstancePerformanceCounters(); 486 _localPCs = new LocalSTPInstancePerformanceCounters();
487 } 487 }
488 488
489 // If the STP is not started suspended then start the threads. 489 // If the STP is not started suspended then start the threads.
490 if (!_isSuspended) 490 if (!_isSuspended)
491 { 491 {
492 StartOptimalNumberOfThreads(); 492 StartOptimalNumberOfThreads();
493 } 493 }
494 } 494 }
495 495
496 private void StartOptimalNumberOfThreads() 496 private void StartOptimalNumberOfThreads()
497 { 497 {
498 int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads); 498 int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads);
499 threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads); 499 threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads);
500 threadsCount -= _workerThreads.Count; 500 threadsCount -= _workerThreads.Count;
501 if (threadsCount > 0) 501 if (threadsCount > 0)
502 { 502 {
503 StartThreads(threadsCount); 503 StartThreads(threadsCount);
504 } 504 }
505 } 505 }
506 506
507 private void ValidateSTPStartInfo() 507 private void ValidateSTPStartInfo()
508 { 508 {
509 if (_stpStartInfo.MinWorkerThreads < 0) 509 if (_stpStartInfo.MinWorkerThreads < 0)
510 { 510 {
511 throw new ArgumentOutOfRangeException( 511 throw new ArgumentOutOfRangeException(
512 "MinWorkerThreads", "MinWorkerThreads cannot be negative"); 512 "MinWorkerThreads", "MinWorkerThreads cannot be negative");
513 } 513 }
514 514
515 if (_stpStartInfo.MaxWorkerThreads <= 0) 515 if (_stpStartInfo.MaxWorkerThreads <= 0)
516 { 516 {
517 throw new ArgumentOutOfRangeException( 517 throw new ArgumentOutOfRangeException(
518 "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero"); 518 "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero");
519 } 519 }
520 520
521 if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads) 521 if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads)
522 { 522 {
523 throw new ArgumentOutOfRangeException( 523 throw new ArgumentOutOfRangeException(
524 "MinWorkerThreads, maxWorkerThreads", 524 "MinWorkerThreads, maxWorkerThreads",
525 "MaxWorkerThreads must be greater or equal to MinWorkerThreads"); 525 "MaxWorkerThreads must be greater or equal to MinWorkerThreads");
526 } 526 }
527 } 527 }
528 528
529 private static void ValidateCallback(Delegate callback) 529 private static void ValidateCallback(Delegate callback)
530 { 530 {
531 if(callback.GetInvocationList().Length > 1) 531 if(callback.GetInvocationList().Length > 1)
532 { 532 {
533 throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); 533 throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
534 } 534 }
535 } 535 }
536 536
537 #endregion 537 #endregion
538 538
539 #region Thread Processing 539 #region Thread Processing
540 540
541 /// <summary> 541 /// <summary>
542 /// Waits on the queue for a work item, shutdown, or timeout. 542 /// Waits on the queue for a work item, shutdown, or timeout.
543 /// </summary> 543 /// </summary>
544 /// <returns> 544 /// <returns>
545 /// Returns the WaitingCallback or null in case of timeout or shutdown. 545 /// Returns the WaitingCallback or null in case of timeout or shutdown.
546 /// </returns> 546 /// </returns>
547 private WorkItem Dequeue() 547 private WorkItem Dequeue()
548 { 548 {
549 WorkItem workItem = 549 WorkItem workItem =
550 _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); 550 _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent);
551 551
552 return workItem; 552 return workItem;
553 } 553 }
554 554
555 /// <summary> 555 /// <summary>
556 /// Put a new work item in the queue 556 /// Put a new work item in the queue
557 /// </summary> 557 /// </summary>
558 /// <param name="workItem">A work item to queue</param> 558 /// <param name="workItem">A work item to queue</param>
559 internal override void Enqueue(WorkItem workItem) 559 internal override void Enqueue(WorkItem workItem)
560 { 560 {
561 // Make sure the workItem is not null 561 // Make sure the workItem is not null
562 Debug.Assert(null != workItem); 562 Debug.Assert(null != workItem);
563 563
564 IncrementWorkItemsCount(); 564 IncrementWorkItemsCount();
565 565
566 workItem.CanceledSmartThreadPool = _canceledSmartThreadPool; 566 workItem.CanceledSmartThreadPool = _canceledSmartThreadPool;
567 _workItemsQueue.EnqueueWorkItem(workItem); 567 _workItemsQueue.EnqueueWorkItem(workItem);
568 workItem.WorkItemIsQueued(); 568 workItem.WorkItemIsQueued();
569 569
570 // If all the threads are busy then try to create a new one 570 // If all the threads are busy then try to create a new one
571 if (_currentWorkItemsCount > _workerThreads.Count) 571 if (_currentWorkItemsCount > _workerThreads.Count)
572 { 572 {
573 StartThreads(1); 573 StartThreads(1);
574 } 574 }
575 } 575 }
576 576
577 private void IncrementWorkItemsCount() 577 private void IncrementWorkItemsCount()
578 { 578 {
579 _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); 579 _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
580 _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); 580 _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
581 581
582 int count = Interlocked.Increment(ref _currentWorkItemsCount); 582 int count = Interlocked.Increment(ref _currentWorkItemsCount);
583 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); 583 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString());
584 if (count == 1) 584 if (count == 1)
585 { 585 {
586 IsIdle = false; 586 IsIdle = false;
587 _isIdleWaitHandle.Reset(); 587 _isIdleWaitHandle.Reset();
588 } 588 }
589 } 589 }
590 590
591 private void DecrementWorkItemsCount() 591 private void DecrementWorkItemsCount()
592 { 592 {
593 int count = Interlocked.Decrement(ref _currentWorkItemsCount); 593 int count = Interlocked.Decrement(ref _currentWorkItemsCount);
594 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); 594 //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString());
595 if (count == 0) 595 if (count == 0)
@@ -602,81 +602,81 @@ namespace Amib.Threading
602 602
603 if (!_shutdown) 603 if (!_shutdown)
604 { 604 {
605 // The counter counts even if the work item was cancelled 605 // The counter counts even if the work item was cancelled
606 _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); 606 _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
607 _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); 607 _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
608 } 608 }
609 609
610 } 610 }
611 611
612 internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) 612 internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup)
613 { 613 {
614 _workItemsGroups[workItemsGroup] = workItemsGroup; 614 _workItemsGroups[workItemsGroup] = workItemsGroup;
615 } 615 }
616 616
617 internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) 617 internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup)
618 { 618 {
619 if (_workItemsGroups.Contains(workItemsGroup)) 619 if (_workItemsGroups.Contains(workItemsGroup))
620 { 620 {
621 _workItemsGroups.Remove(workItemsGroup); 621 _workItemsGroups.Remove(workItemsGroup);
622 } 622 }
623 } 623 }
624 624
625 /// <summary> 625 /// <summary>
626 /// Inform that the current thread is about to quit or quiting. 626 /// Inform that the current thread is about to quit or quiting.
627 /// The same thread may call this method more than once. 627 /// The same thread may call this method more than once.
628 /// </summary> 628 /// </summary>
629 private void InformCompleted() 629 private void InformCompleted()
630 { 630 {
631 // There is no need to lock the two methods together 631 // There is no need to lock the two methods together
632 // since only the current thread removes itself 632 // since only the current thread removes itself
633 // and the _workerThreads is a synchronized dictionary 633 // and the _workerThreads is a synchronized dictionary
634 if (_workerThreads.Contains(Thread.CurrentThread)) 634 if (_workerThreads.Contains(Thread.CurrentThread))
635 { 635 {
636 _workerThreads.Remove(Thread.CurrentThread); 636 _workerThreads.Remove(Thread.CurrentThread);
637 _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); 637 _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
638 _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); 638 _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
639 } 639 }
640 } 640 }
641 641
642 /// <summary> 642 /// <summary>
643 /// Starts new threads 643 /// Starts new threads
644 /// </summary> 644 /// </summary>
645 /// <param name="threadsCount">The number of threads to start</param> 645 /// <param name="threadsCount">The number of threads to start</param>
646 private void StartThreads(int threadsCount) 646 private void StartThreads(int threadsCount)
647 { 647 {
648 if (_isSuspended) 648 if (_isSuspended)
649 { 649 {
650 return; 650 return;
651 } 651 }
652 652
653 lock(_workerThreads.SyncRoot) 653 lock(_workerThreads.SyncRoot)
654 { 654 {
655 // Don't start threads on shut down 655 // Don't start threads on shut down
656 if (_shutdown) 656 if (_shutdown)
657 { 657 {
658 return; 658 return;
659 } 659 }
660 660
661 for(int i = 0; i < threadsCount; ++i) 661 for(int i = 0; i < threadsCount; ++i)
662 { 662 {
663 // Don't create more threads then the upper limit 663 // Don't create more threads then the upper limit
664 if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) 664 if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads)
665 { 665 {
666 return; 666 return;
667 } 667 }
668 668
669 // Create a new thread 669 // Create a new thread
670 670
671#if (_SILVERLIGHT) || (WINDOWS_PHONE) 671#if (_SILVERLIGHT) || (WINDOWS_PHONE)
672 Thread workerThread = new Thread(ProcessQueuedItems); 672 Thread workerThread = new Thread(ProcessQueuedItems);
673#else 673#else
674 Thread workerThread = 674 Thread workerThread =
675 _stpStartInfo.MaxStackSize.HasValue 675 _stpStartInfo.MaxStackSize.HasValue
676 ? new Thread(ProcessQueuedItems, _stpStartInfo.MaxStackSize.Value) 676 ? new Thread(ProcessQueuedItems, _stpStartInfo.MaxStackSize.Value)
677 : new Thread(ProcessQueuedItems); 677 : new Thread(ProcessQueuedItems);
678#endif 678#endif
679 // Configure the new thread and start it 679 // Configure the new thread and start it
680 workerThread.IsBackground = _stpStartInfo.AreThreadsBackground; 680 workerThread.IsBackground = _stpStartInfo.AreThreadsBackground;
681 681
682#if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE) 682#if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE)
@@ -697,32 +697,32 @@ namespace Amib.Threading
697 // Add it to the dictionary and update its creation time. 697 // Add it to the dictionary and update its creation time.
698 _workerThreads[workerThread] = new ThreadEntry(this); 698 _workerThreads[workerThread] = new ThreadEntry(this);
699 699
700 _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); 700 _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
701 _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); 701 _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
702 } 702 }
703 } 703 }
704 } 704 }
705 705
706 /// <summary> 706 /// <summary>
707 /// A worker thread method that processes work items from the work items queue. 707 /// A worker thread method that processes work items from the work items queue.
708 /// </summary> 708 /// </summary>
709 private void ProcessQueuedItems() 709 private void ProcessQueuedItems()
710 { 710 {
711 // Keep the entry of the dictionary as thread's variable to avoid the synchronization locks 711 // Keep the entry of the dictionary as thread's variable to avoid the synchronization locks
712 // of the dictionary. 712 // of the dictionary.
713 CurrentThreadEntry = _workerThreads[Thread.CurrentThread]; 713 CurrentThreadEntry = _workerThreads[Thread.CurrentThread];
714 714
715 FireOnThreadInitialization(); 715 FireOnThreadInitialization();
716 716
717 try 717 try
718 { 718 {
719 bool bInUseWorkerThreadsWasIncremented = false; 719 bool bInUseWorkerThreadsWasIncremented = false;
720 720
721 // Process until shutdown. 721 // Process until shutdown.
722 while(!_shutdown) 722 while(!_shutdown)
723 { 723 {
724 // Update the last time this thread was seen alive. 724 // Update the last time this thread was seen alive.
725 // It's good for debugging. 725 // It's good for debugging.
726 CurrentThreadEntry.IAmAlive(); 726 CurrentThreadEntry.IAmAlive();
727 727
728 // The following block handles the when the MaxWorkerThreads has been 728 // The following block handles the when the MaxWorkerThreads has been
@@ -744,166 +744,166 @@ namespace Amib.Threading
744 } 744 }
745 } 745 }
746 746
747 // Wait for a work item, shutdown, or timeout 747 // Wait for a work item, shutdown, or timeout
748 WorkItem workItem = Dequeue(); 748 WorkItem workItem = Dequeue();
749 749
750 // Update the last time this thread was seen alive. 750 // Update the last time this thread was seen alive.
751 // It's good for debugging. 751 // It's good for debugging.
752 CurrentThreadEntry.IAmAlive(); 752 CurrentThreadEntry.IAmAlive();
753 753
754 // On timeout or shut down. 754 // On timeout or shut down.
755 if (null == workItem) 755 if (null == workItem)
756 { 756 {
757 // Double lock for quit. 757 // Double lock for quit.
758 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) 758 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads)
759 { 759 {
760 lock(_workerThreads.SyncRoot) 760 lock(_workerThreads.SyncRoot)
761 { 761 {
762 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) 762 if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads)
763 { 763 {
764 // Inform that the thread is quiting and then quit. 764 // Inform that the thread is quiting and then quit.
765 // This method must be called within this lock or else 765 // This method must be called within this lock or else
766 // more threads will quit and the thread pool will go 766 // more threads will quit and the thread pool will go
767 // below the lower limit. 767 // below the lower limit.
768 InformCompleted(); 768 InformCompleted();
769 break; 769 break;
770 } 770 }
771 } 771 }
772 } 772 }
773 } 773 }
774 774
775 // If we didn't quit then skip to the next iteration. 775 // If we didn't quit then skip to the next iteration.
776 if (null == workItem) 776 if (null == workItem)
777 { 777 {
778 continue; 778 continue;
779 } 779 }
780 780
781 try 781 try
782 { 782 {
783 // Initialize the value to false 783 // Initialize the value to false
784 bInUseWorkerThreadsWasIncremented = false; 784 bInUseWorkerThreadsWasIncremented = false;
785 785
786 // Set the Current Work Item of the thread. 786 // Set the Current Work Item of the thread.
787 // Store the Current Work Item before the workItem.StartingWorkItem() is called, 787 // Store the Current Work Item before the workItem.StartingWorkItem() is called,
788 // so WorkItem.Cancel can work when the work item is between InQueue and InProgress 788 // so WorkItem.Cancel can work when the work item is between InQueue and InProgress
789 // states. 789 // states.
790 // If the work item has been cancelled BEFORE the workItem.StartingWorkItem() 790 // If the work item has been cancelled BEFORE the workItem.StartingWorkItem()
791 // (work item is in InQueue state) then workItem.StartingWorkItem() will return false. 791 // (work item is in InQueue state) then workItem.StartingWorkItem() will return false.
792 // If the work item has been cancelled AFTER the workItem.StartingWorkItem() then 792 // If the work item has been cancelled AFTER the workItem.StartingWorkItem() then
793 // (work item is in InProgress state) then the thread will be aborted 793 // (work item is in InProgress state) then the thread will be aborted
794 CurrentThreadEntry.CurrentWorkItem = workItem; 794 CurrentThreadEntry.CurrentWorkItem = workItem;
795 795
796 // Change the state of the work item to 'in progress' if possible. 796 // Change the state of the work item to 'in progress' if possible.
797 // We do it here so if the work item has been canceled we won't 797 // We do it here so if the work item has been canceled we won't
798 // increment the _inUseWorkerThreads. 798 // increment the _inUseWorkerThreads.
799 // The cancel mechanism doesn't delete items from the queue, 799 // The cancel mechanism doesn't delete items from the queue,
800 // it marks the work item as canceled, and when the work item 800 // it marks the work item as canceled, and when the work item
801 // is dequeued, we just skip it. 801 // is dequeued, we just skip it.
802 // If the post execute of work item is set to always or to 802 // If the post execute of work item is set to always or to
803 // call when the work item is canceled then the StartingWorkItem() 803 // call when the work item is canceled then the StartingWorkItem()
804 // will return true, so the post execute can run. 804 // will return true, so the post execute can run.
805 if (!workItem.StartingWorkItem()) 805 if (!workItem.StartingWorkItem())
806 { 806 {
807 continue; 807 continue;
808 } 808 }
809 809
810 // Execute the callback. Make sure to accurately 810 // Execute the callback. Make sure to accurately
811 // record how many callbacks are currently executing. 811 // record how many callbacks are currently executing.
812 int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads); 812 int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads);
813 _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); 813 _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
814 _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); 814 _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
815 815
816 // Mark that the _inUseWorkerThreads incremented, so in the finally{} 816 // Mark that the _inUseWorkerThreads incremented, so in the finally{}
817 // statement we will decrement it correctly. 817 // statement we will decrement it correctly.
818 bInUseWorkerThreadsWasIncremented = true; 818 bInUseWorkerThreadsWasIncremented = true;
819 819
820 workItem.FireWorkItemStarted(); 820 workItem.FireWorkItemStarted();
821 821
822 ExecuteWorkItem(workItem); 822 ExecuteWorkItem(workItem);
823 } 823 }
824 catch(Exception ex) 824 catch(Exception ex)
825 { 825 {
826 ex.GetHashCode(); 826 ex.GetHashCode();
827 // Do nothing 827 // Do nothing
828 } 828 }
829 finally 829 finally
830 { 830 {
831 workItem.DisposeOfState(); 831 workItem.DisposeOfState();
832 832
833 // Set the CurrentWorkItem to null, since we 833 // Set the CurrentWorkItem to null, since we
834 // no longer run user's code. 834 // no longer run user's code.
835 CurrentThreadEntry.CurrentWorkItem = null; 835 CurrentThreadEntry.CurrentWorkItem = null;
836 836
837 // Decrement the _inUseWorkerThreads only if we had 837 // Decrement the _inUseWorkerThreads only if we had
838 // incremented it. Note the cancelled work items don't 838 // incremented it. Note the cancelled work items don't
839 // increment _inUseWorkerThreads. 839 // increment _inUseWorkerThreads.
840 if (bInUseWorkerThreadsWasIncremented) 840 if (bInUseWorkerThreadsWasIncremented)
841 { 841 {
842 int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads); 842 int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads);
843 _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); 843 _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
844 _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); 844 _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
845 } 845 }
846 846
847 // Notify that the work item has been completed. 847 // Notify that the work item has been completed.
848 // WorkItemsGroup may enqueue their next work item. 848 // WorkItemsGroup may enqueue their next work item.
849 workItem.FireWorkItemCompleted(); 849 workItem.FireWorkItemCompleted();
850 850
851 // Decrement the number of work items here so the idle 851 // Decrement the number of work items here so the idle
852 // ManualResetEvent won't fluctuate. 852 // ManualResetEvent won't fluctuate.
853 DecrementWorkItemsCount(); 853 DecrementWorkItemsCount();
854 } 854 }
855 } 855 }
856 } 856 }
857 catch(ThreadAbortException tae) 857 catch(ThreadAbortException tae)
858 { 858 {
859 tae.GetHashCode(); 859 tae.GetHashCode();
860 // Handle the abort exception gracfully. 860 // Handle the abort exception gracfully.
861#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) 861#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
862 Thread.ResetAbort(); 862 Thread.ResetAbort();
863#endif 863#endif
864 } 864 }
865 catch(Exception e) 865 catch(Exception e)
866 { 866 {
867 Debug.Assert(null != e); 867 Debug.Assert(null != e);
868 } 868 }
869 finally 869 finally
870 { 870 {
871 InformCompleted(); 871 InformCompleted();
872 FireOnThreadTermination(); 872 FireOnThreadTermination();
873 } 873 }
874 } 874 }
875 875
876 private void ExecuteWorkItem(WorkItem workItem) 876 private void ExecuteWorkItem(WorkItem workItem)
877 { 877 {
878 _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); 878 _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime);
879 _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); 879 _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime);
880 try 880 try
881 { 881 {
882 workItem.Execute(); 882 workItem.Execute();
883 } 883 }
884 finally 884 finally
885 { 885 {
886 _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); 886 _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime);
887 _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); 887 _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime);
888 } 888 }
889 } 889 }
890 890
891 891
892 #endregion 892 #endregion
893 893
894 #region Public Methods 894 #region Public Methods
895 895
896 private void ValidateWaitForIdle() 896 private void ValidateWaitForIdle()
897 { 897 {
898 if (null != CurrentThreadEntry && CurrentThreadEntry.AssociatedSmartThreadPool == this) 898 if (null != CurrentThreadEntry && CurrentThreadEntry.AssociatedSmartThreadPool == this)
899 { 899 {
900 throw new NotSupportedException( 900 throw new NotSupportedException(
901 "WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); 901 "WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock");
902 } 902 }
903 } 903 }
904 904
905 internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup) 905 internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup)
906 { 906 {
907 if (null == CurrentThreadEntry) 907 if (null == CurrentThreadEntry)
908 { 908 {
909 return; 909 return;
@@ -911,334 +911,334 @@ namespace Amib.Threading
911 911
912 WorkItem workItem = CurrentThreadEntry.CurrentWorkItem; 912 WorkItem workItem = CurrentThreadEntry.CurrentWorkItem;
913 ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem); 913 ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem);
914 if ((null != workItemsGroup) && 914 if ((null != workItemsGroup) &&
915 (null != workItem) && 915 (null != workItem) &&
916 CurrentThreadEntry.CurrentWorkItem.WasQueuedBy(workItemsGroup)) 916 CurrentThreadEntry.CurrentWorkItem.WasQueuedBy(workItemsGroup))
917 { 917 {
918 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); 918 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock");
919 } 919 }
920 } 920 }
921 921
922 [MethodImpl(MethodImplOptions.NoInlining)] 922 [MethodImpl(MethodImplOptions.NoInlining)]
923 private static void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem) 923 private static void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem)
924 { 924 {
925 if ((null != workItemsGroup) && 925 if ((null != workItemsGroup) &&
926 (null != workItem) && 926 (null != workItem) &&
927 workItem.WasQueuedBy(workItemsGroup)) 927 workItem.WasQueuedBy(workItemsGroup))
928 { 928 {
929 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); 929 throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock");
930 } 930 }
931 } 931 }
932 932
933 /// <summary> 933 /// <summary>
934 /// Force the SmartThreadPool to shutdown 934 /// Force the SmartThreadPool to shutdown
935 /// </summary> 935 /// </summary>
936 public void Shutdown() 936 public void Shutdown()
937 { 937 {
938 Shutdown(true, 0); 938 Shutdown(true, 0);
939 } 939 }
940 940
941 /// <summary> 941 /// <summary>
942 /// Force the SmartThreadPool to shutdown with timeout 942 /// Force the SmartThreadPool to shutdown with timeout
943 /// </summary> 943 /// </summary>
944 public void Shutdown(bool forceAbort, TimeSpan timeout) 944 public void Shutdown(bool forceAbort, TimeSpan timeout)
945 { 945 {
946 Shutdown(forceAbort, (int)timeout.TotalMilliseconds); 946 Shutdown(forceAbort, (int)timeout.TotalMilliseconds);
947 } 947 }
948 948
949 /// <summary> 949 /// <summary>
950 /// Empties the queue of work items and abort the threads in the pool. 950 /// Empties the queue of work items and abort the threads in the pool.
951 /// </summary> 951 /// </summary>
952 public void Shutdown(bool forceAbort, int millisecondsTimeout) 952 public void Shutdown(bool forceAbort, int millisecondsTimeout)
953 { 953 {
954 ValidateNotDisposed(); 954 ValidateNotDisposed();
955 955
956 ISTPInstancePerformanceCounters pcs = _windowsPCs; 956 ISTPInstancePerformanceCounters pcs = _windowsPCs;
957 957
958 if (NullSTPInstancePerformanceCounters.Instance != _windowsPCs) 958 if (NullSTPInstancePerformanceCounters.Instance != _windowsPCs)
959 { 959 {
960 // Set the _pcs to "null" to stop updating the performance 960 // Set the _pcs to "null" to stop updating the performance
961 // counters 961 // counters
962 _windowsPCs = NullSTPInstancePerformanceCounters.Instance; 962 _windowsPCs = NullSTPInstancePerformanceCounters.Instance;
963 963
964 pcs.Dispose(); 964 pcs.Dispose();
965 } 965 }
966 966
967 Thread [] threads; 967 Thread [] threads;
968 lock(_workerThreads.SyncRoot) 968 lock(_workerThreads.SyncRoot)
969 { 969 {
970 // Shutdown the work items queue 970 // Shutdown the work items queue
971 _workItemsQueue.Dispose(); 971 _workItemsQueue.Dispose();
972 972
973 // Signal the threads to exit 973 // Signal the threads to exit
974 _shutdown = true; 974 _shutdown = true;
975 _shuttingDownEvent.Set(); 975 _shuttingDownEvent.Set();
976 976
977 // Make a copy of the threads' references in the pool 977 // Make a copy of the threads' references in the pool
978 threads = new Thread [_workerThreads.Count]; 978 threads = new Thread [_workerThreads.Count];
979 _workerThreads.Keys.CopyTo(threads, 0); 979 _workerThreads.Keys.CopyTo(threads, 0);
980 } 980 }
981 981
982 int millisecondsLeft = millisecondsTimeout; 982 int millisecondsLeft = millisecondsTimeout;
983 Stopwatch stopwatch = Stopwatch.StartNew(); 983 Stopwatch stopwatch = Stopwatch.StartNew();
984 //DateTime start = DateTime.UtcNow; 984 //DateTime start = DateTime.UtcNow;
985 bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); 985 bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
986 bool timeout = false; 986 bool timeout = false;
987 987
988 // Each iteration we update the time left for the timeout. 988 // Each iteration we update the time left for the timeout.
989 foreach(Thread thread in threads) 989 foreach(Thread thread in threads)
990 { 990 {
991 // Join don't work with negative numbers 991 // Join don't work with negative numbers
992 if (!waitInfinitely && (millisecondsLeft < 0)) 992 if (!waitInfinitely && (millisecondsLeft < 0))
993 { 993 {
994 timeout = true; 994 timeout = true;
995 break; 995 break;
996 } 996 }
997 997
998 // Wait for the thread to terminate 998 // Wait for the thread to terminate
999 bool success = thread.Join(millisecondsLeft); 999 bool success = thread.Join(millisecondsLeft);
1000 if(!success) 1000 if(!success)
1001 { 1001 {
1002 timeout = true; 1002 timeout = true;
1003 break; 1003 break;
1004 } 1004 }
1005 1005
1006 if(!waitInfinitely) 1006 if(!waitInfinitely)
1007 { 1007 {
1008 // Update the time left to wait 1008 // Update the time left to wait
1009 //TimeSpan ts = DateTime.UtcNow - start; 1009 //TimeSpan ts = DateTime.UtcNow - start;
1010 millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds; 1010 millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds;
1011 } 1011 }
1012 } 1012 }
1013 1013
1014 if (timeout && forceAbort) 1014 if (timeout && forceAbort)
1015 { 1015 {
1016 // Abort the threads in the pool 1016 // Abort the threads in the pool
1017 foreach(Thread thread in threads) 1017 foreach(Thread thread in threads)
1018 { 1018 {
1019 1019
1020 if ((thread != null) 1020 if ((thread != null)
1021#if !(_WINDOWS_CE) 1021#if !(_WINDOWS_CE)
1022 && thread.IsAlive 1022 && thread.IsAlive
1023#endif 1023#endif
1024 ) 1024 )
1025 { 1025 {
1026 try 1026 try
1027 { 1027 {
1028 thread.Abort(); // Shutdown 1028 thread.Abort(); // Shutdown
1029 } 1029 }
1030 catch(SecurityException e) 1030 catch(SecurityException e)
1031 { 1031 {
1032 e.GetHashCode(); 1032 e.GetHashCode();
1033 } 1033 }
1034 catch(ThreadStateException ex) 1034 catch(ThreadStateException ex)
1035 { 1035 {
1036 ex.GetHashCode(); 1036 ex.GetHashCode();
1037 // In case the thread has been terminated 1037 // In case the thread has been terminated
1038 // after the check if it is alive. 1038 // after the check if it is alive.
1039 } 1039 }
1040 } 1040 }
1041 } 1041 }
1042 } 1042 }
1043 } 1043 }
1044 1044
1045 /// <summary> 1045 /// <summary>
1046 /// Wait for all work items to complete 1046 /// Wait for all work items to complete
1047 /// </summary> 1047 /// </summary>
1048 /// <param name="waitableResults">Array of work item result objects</param> 1048 /// <param name="waitableResults">Array of work item result objects</param>
1049 /// <returns> 1049 /// <returns>
1050 /// true when every work item in workItemResults has completed; otherwise false. 1050 /// true when every work item in workItemResults has completed; otherwise false.
1051 /// </returns> 1051 /// </returns>
1052 public static bool WaitAll( 1052 public static bool WaitAll(
1053 IWaitableResult [] waitableResults) 1053 IWaitableResult [] waitableResults)
1054 { 1054 {
1055 return WaitAll(waitableResults, Timeout.Infinite, true); 1055 return WaitAll(waitableResults, Timeout.Infinite, true);
1056 } 1056 }
1057 1057
1058 /// <summary> 1058 /// <summary>
1059 /// Wait for all work items to complete 1059 /// Wait for all work items to complete
1060 /// </summary> 1060 /// </summary>
1061 /// <param name="waitableResults">Array of work item result objects</param> 1061 /// <param name="waitableResults">Array of work item result objects</param>
1062 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1062 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1063 /// <param name="exitContext"> 1063 /// <param name="exitContext">
1064 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1064 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1065 /// </param> 1065 /// </param>
1066 /// <returns> 1066 /// <returns>
1067 /// true when every work item in workItemResults has completed; otherwise false. 1067 /// true when every work item in workItemResults has completed; otherwise false.
1068 /// </returns> 1068 /// </returns>
1069 public static bool WaitAll( 1069 public static bool WaitAll(
1070 IWaitableResult [] waitableResults, 1070 IWaitableResult [] waitableResults,
1071 TimeSpan timeout, 1071 TimeSpan timeout,
1072 bool exitContext) 1072 bool exitContext)
1073 { 1073 {
1074 return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext); 1074 return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext);
1075 } 1075 }
1076 1076
1077 /// <summary> 1077 /// <summary>
1078 /// Wait for all work items to complete 1078 /// Wait for all work items to complete
1079 /// </summary> 1079 /// </summary>
1080 /// <param name="waitableResults">Array of work item result objects</param> 1080 /// <param name="waitableResults">Array of work item result objects</param>
1081 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1081 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1082 /// <param name="exitContext"> 1082 /// <param name="exitContext">
1083 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1083 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1084 /// </param> 1084 /// </param>
1085 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 1085 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1086 /// <returns> 1086 /// <returns>
1087 /// true when every work item in workItemResults has completed; otherwise false. 1087 /// true when every work item in workItemResults has completed; otherwise false.
1088 /// </returns> 1088 /// </returns>
1089 public static bool WaitAll( 1089 public static bool WaitAll(
1090 IWaitableResult[] waitableResults, 1090 IWaitableResult[] waitableResults,
1091 TimeSpan timeout, 1091 TimeSpan timeout,
1092 bool exitContext, 1092 bool exitContext,
1093 WaitHandle cancelWaitHandle) 1093 WaitHandle cancelWaitHandle)
1094 { 1094 {
1095 return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); 1095 return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
1096 } 1096 }
1097 1097
1098 /// <summary> 1098 /// <summary>
1099 /// Wait for all work items to complete 1099 /// Wait for all work items to complete
1100 /// </summary> 1100 /// </summary>
1101 /// <param name="waitableResults">Array of work item result objects</param> 1101 /// <param name="waitableResults">Array of work item result objects</param>
1102 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 1102 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1103 /// <param name="exitContext"> 1103 /// <param name="exitContext">
1104 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1104 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1105 /// </param> 1105 /// </param>
1106 /// <returns> 1106 /// <returns>
1107 /// true when every work item in workItemResults has completed; otherwise false. 1107 /// true when every work item in workItemResults has completed; otherwise false.
1108 /// </returns> 1108 /// </returns>
1109 public static bool WaitAll( 1109 public static bool WaitAll(
1110 IWaitableResult [] waitableResults, 1110 IWaitableResult [] waitableResults,
1111 int millisecondsTimeout, 1111 int millisecondsTimeout,
1112 bool exitContext) 1112 bool exitContext)
1113 { 1113 {
1114 return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null); 1114 return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null);
1115 } 1115 }
1116 1116
1117 /// <summary> 1117 /// <summary>
1118 /// Wait for all work items to complete 1118 /// Wait for all work items to complete
1119 /// </summary> 1119 /// </summary>
1120 /// <param name="waitableResults">Array of work item result objects</param> 1120 /// <param name="waitableResults">Array of work item result objects</param>
1121 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 1121 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1122 /// <param name="exitContext"> 1122 /// <param name="exitContext">
1123 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1123 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1124 /// </param> 1124 /// </param>
1125 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 1125 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1126 /// <returns> 1126 /// <returns>
1127 /// true when every work item in workItemResults has completed; otherwise false. 1127 /// true when every work item in workItemResults has completed; otherwise false.
1128 /// </returns> 1128 /// </returns>
1129 public static bool WaitAll( 1129 public static bool WaitAll(
1130 IWaitableResult[] waitableResults, 1130 IWaitableResult[] waitableResults,
1131 int millisecondsTimeout, 1131 int millisecondsTimeout,
1132 bool exitContext, 1132 bool exitContext,
1133 WaitHandle cancelWaitHandle) 1133 WaitHandle cancelWaitHandle)
1134 { 1134 {
1135 return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); 1135 return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle);
1136 } 1136 }
1137 1137
1138 1138
1139 /// <summary> 1139 /// <summary>
1140 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1140 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1141 /// </summary> 1141 /// </summary>
1142 /// <param name="waitableResults">Array of work item result objects</param> 1142 /// <param name="waitableResults">Array of work item result objects</param>
1143 /// <returns> 1143 /// <returns>
1144 /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled. 1144 /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled.
1145 /// </returns> 1145 /// </returns>
1146 public static int WaitAny( 1146 public static int WaitAny(
1147 IWaitableResult [] waitableResults) 1147 IWaitableResult [] waitableResults)
1148 { 1148 {
1149 return WaitAny(waitableResults, Timeout.Infinite, true); 1149 return WaitAny(waitableResults, Timeout.Infinite, true);
1150 } 1150 }
1151 1151
1152 /// <summary> 1152 /// <summary>
1153 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1153 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1154 /// </summary> 1154 /// </summary>
1155 /// <param name="waitableResults">Array of work item result objects</param> 1155 /// <param name="waitableResults">Array of work item result objects</param>
1156 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1156 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1157 /// <param name="exitContext"> 1157 /// <param name="exitContext">
1158 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1158 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1159 /// </param> 1159 /// </param>
1160 /// <returns> 1160 /// <returns>
1161 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 1161 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1162 /// </returns> 1162 /// </returns>
1163 public static int WaitAny( 1163 public static int WaitAny(
1164 IWaitableResult[] waitableResults, 1164 IWaitableResult[] waitableResults,
1165 TimeSpan timeout, 1165 TimeSpan timeout,
1166 bool exitContext) 1166 bool exitContext)
1167 { 1167 {
1168 return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext); 1168 return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext);
1169 } 1169 }
1170 1170
1171 /// <summary> 1171 /// <summary>
1172 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1172 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1173 /// </summary> 1173 /// </summary>
1174 /// <param name="waitableResults">Array of work item result objects</param> 1174 /// <param name="waitableResults">Array of work item result objects</param>
1175 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param> 1175 /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
1176 /// <param name="exitContext"> 1176 /// <param name="exitContext">
1177 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1177 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1178 /// </param> 1178 /// </param>
1179 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 1179 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1180 /// <returns> 1180 /// <returns>
1181 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 1181 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1182 /// </returns> 1182 /// </returns>
1183 public static int WaitAny( 1183 public static int WaitAny(
1184 IWaitableResult [] waitableResults, 1184 IWaitableResult [] waitableResults,
1185 TimeSpan timeout, 1185 TimeSpan timeout,
1186 bool exitContext, 1186 bool exitContext,
1187 WaitHandle cancelWaitHandle) 1187 WaitHandle cancelWaitHandle)
1188 { 1188 {
1189 return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); 1189 return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
1190 } 1190 }
1191 1191
1192 /// <summary> 1192 /// <summary>
1193 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1193 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1194 /// </summary> 1194 /// </summary>
1195 /// <param name="waitableResults">Array of work item result objects</param> 1195 /// <param name="waitableResults">Array of work item result objects</param>
1196 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 1196 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1197 /// <param name="exitContext"> 1197 /// <param name="exitContext">
1198 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1198 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1199 /// </param> 1199 /// </param>
1200 /// <returns> 1200 /// <returns>
1201 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 1201 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1202 /// </returns> 1202 /// </returns>
1203 public static int WaitAny( 1203 public static int WaitAny(
1204 IWaitableResult [] waitableResults, 1204 IWaitableResult [] waitableResults,
1205 int millisecondsTimeout, 1205 int millisecondsTimeout,
1206 bool exitContext) 1206 bool exitContext)
1207 { 1207 {
1208 return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null); 1208 return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null);
1209 } 1209 }
1210 1210
1211 /// <summary> 1211 /// <summary>
1212 /// Waits for any of the work items in the specified array to complete, cancel, or timeout 1212 /// Waits for any of the work items in the specified array to complete, cancel, or timeout
1213 /// </summary> 1213 /// </summary>
1214 /// <param name="waitableResults">Array of work item result objects</param> 1214 /// <param name="waitableResults">Array of work item result objects</param>
1215 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param> 1215 /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
1216 /// <param name="exitContext"> 1216 /// <param name="exitContext">
1217 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 1217 /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
1218 /// </param> 1218 /// </param>
1219 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param> 1219 /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
1220 /// <returns> 1220 /// <returns>
1221 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. 1221 /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
1222 /// </returns> 1222 /// </returns>
1223 public static int WaitAny( 1223 public static int WaitAny(
1224 IWaitableResult [] waitableResults, 1224 IWaitableResult [] waitableResults,
1225 int millisecondsTimeout, 1225 int millisecondsTimeout,
1226 bool exitContext, 1226 bool exitContext,
1227 WaitHandle cancelWaitHandle) 1227 WaitHandle cancelWaitHandle)
1228 { 1228 {
1229 return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); 1229 return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle);
1230 } 1230 }
1231 1231
1232 /// <summary> 1232 /// <summary>
1233 /// Creates a new WorkItemsGroup. 1233 /// Creates a new WorkItemsGroup.
1234 /// </summary> 1234 /// </summary>
1235 /// <param name="concurrency">The number of work items that can be run concurrently</param> 1235 /// <param name="concurrency">The number of work items that can be run concurrently</param>
1236 /// <returns>A reference to the WorkItemsGroup</returns> 1236 /// <returns>A reference to the WorkItemsGroup</returns>
1237 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency) 1237 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency)
1238 { 1238 {
1239 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo); 1239 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo);
1240 return workItemsGroup; 1240 return workItemsGroup;
1241 } 1241 }
1242 1242
1243 /// <summary> 1243 /// <summary>
1244 /// Creates a new WorkItemsGroup. 1244 /// Creates a new WorkItemsGroup.
@@ -1246,11 +1246,11 @@ namespace Amib.Threading
1246 /// <param name="concurrency">The number of work items that can be run concurrently</param> 1246 /// <param name="concurrency">The number of work items that can be run concurrently</param>
1247 /// <param name="wigStartInfo">A WorkItemsGroup configuration that overrides the default behavior</param> 1247 /// <param name="wigStartInfo">A WorkItemsGroup configuration that overrides the default behavior</param>
1248 /// <returns>A reference to the WorkItemsGroup</returns> 1248 /// <returns>A reference to the WorkItemsGroup</returns>
1249 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo) 1249 public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo)
1250 { 1250 {
1251 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo); 1251 IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo);
1252 return workItemsGroup; 1252 return workItemsGroup;
1253 } 1253 }
1254 1254
1255 #region Fire Thread's Events 1255 #region Fire Thread's Events
1256 1256
@@ -1331,22 +1331,22 @@ namespace Amib.Threading
1331 } 1331 }
1332 } 1332 }
1333 1333
1334
1335 1334
1336 #endregion
1337 1335
1338 #region Properties 1336 #endregion
1337
1338 #region Properties
1339 1339
1340 /// <summary> 1340 /// <summary>
1341 /// Get/Set the lower limit of threads in the pool. 1341 /// Get/Set the lower limit of threads in the pool.
1342 /// </summary> 1342 /// </summary>
1343 public int MinThreads 1343 public int MinThreads
1344 { 1344 {
1345 get 1345 get
1346 { 1346 {
1347 ValidateNotDisposed(); 1347 ValidateNotDisposed();
1348 return _stpStartInfo.MinWorkerThreads; 1348 return _stpStartInfo.MinWorkerThreads;
1349 } 1349 }
1350 set 1350 set
1351 { 1351 {
1352 Debug.Assert(value >= 0); 1352 Debug.Assert(value >= 0);
@@ -1358,21 +1358,21 @@ namespace Amib.Threading
1358 _stpStartInfo.MinWorkerThreads = value; 1358 _stpStartInfo.MinWorkerThreads = value;
1359 StartOptimalNumberOfThreads(); 1359 StartOptimalNumberOfThreads();
1360 } 1360 }
1361 } 1361 }
1362 1362
1363 /// <summary> 1363 /// <summary>
1364 /// Get/Set the upper limit of threads in the pool. 1364 /// Get/Set the upper limit of threads in the pool.
1365 /// </summary> 1365 /// </summary>
1366 public int MaxThreads 1366 public int MaxThreads
1367 { 1367 {
1368 get 1368 get
1369 { 1369 {
1370 ValidateNotDisposed(); 1370 ValidateNotDisposed();
1371 return _stpStartInfo.MaxWorkerThreads; 1371 return _stpStartInfo.MaxWorkerThreads;
1372 } 1372 }
1373 1373
1374 set 1374 set
1375 { 1375 {
1376 Debug.Assert(value > 0); 1376 Debug.Assert(value > 0);
1377 Debug.Assert(value >= _stpStartInfo.MinWorkerThreads); 1377 Debug.Assert(value >= _stpStartInfo.MinWorkerThreads);
1378 if (_stpStartInfo.MinWorkerThreads > value) 1378 if (_stpStartInfo.MinWorkerThreads > value)
@@ -1381,32 +1381,32 @@ namespace Amib.Threading
1381 } 1381 }
1382 _stpStartInfo.MaxWorkerThreads = value; 1382 _stpStartInfo.MaxWorkerThreads = value;
1383 StartOptimalNumberOfThreads(); 1383 StartOptimalNumberOfThreads();
1384 } 1384 }
1385 } 1385 }
1386 /// <summary> 1386 /// <summary>
1387 /// Get the number of threads in the thread pool. 1387 /// Get the number of threads in the thread pool.
1388 /// Should be between the lower and the upper limits. 1388 /// Should be between the lower and the upper limits.
1389 /// </summary> 1389 /// </summary>
1390 public int ActiveThreads 1390 public int ActiveThreads
1391 { 1391 {
1392 get 1392 get
1393 { 1393 {
1394 ValidateNotDisposed(); 1394 ValidateNotDisposed();
1395 return _workerThreads.Count; 1395 return _workerThreads.Count;
1396 } 1396 }
1397 } 1397 }
1398 1398
1399 /// <summary> 1399 /// <summary>
1400 /// Get the number of busy (not idle) threads in the thread pool. 1400 /// Get the number of busy (not idle) threads in the thread pool.
1401 /// </summary> 1401 /// </summary>
1402 public int InUseThreads 1402 public int InUseThreads
1403 { 1403 {
1404 get 1404 get
1405 { 1405 {
1406 ValidateNotDisposed(); 1406 ValidateNotDisposed();
1407 return _inUseWorkerThreads; 1407 return _inUseWorkerThreads;
1408 } 1408 }
1409 } 1409 }
1410 1410
1411 /// <summary> 1411 /// <summary>
1412 /// Returns true if the current running work item has been cancelled. 1412 /// Returns true if the current running work item has been cancelled.
@@ -1420,8 +1420,8 @@ namespace Amib.Threading
1420 { 1420 {
1421 return CurrentThreadEntry.CurrentWorkItem.IsCanceled; 1421 return CurrentThreadEntry.CurrentWorkItem.IsCanceled;
1422 } 1422 }
1423 } 1423 }
1424 1424
1425 /// <summary> 1425 /// <summary>
1426 /// Checks if the work item has been cancelled, and if yes then abort the thread. 1426 /// Checks if the work item has been cancelled, and if yes then abort the thread.
1427 /// Can be used with Cancel and timeout 1427 /// Can be used with Cancel and timeout
@@ -1439,16 +1439,16 @@ namespace Amib.Threading
1439 /// </summary> 1439 /// </summary>
1440 public STPStartInfo STPStartInfo 1440 public STPStartInfo STPStartInfo
1441 { 1441 {
1442 get 1442 get
1443 { 1443 {
1444 return _stpStartInfo.AsReadOnly(); 1444 return _stpStartInfo.AsReadOnly();
1445 } 1445 }
1446 } 1446 }
1447 1447
1448 public bool IsShuttingdown 1448 public bool IsShuttingdown
1449 { 1449 {
1450 get { return _shutdown; } 1450 get { return _shutdown; }
1451 } 1451 }
1452 1452
1453 /// <summary> 1453 /// <summary>
1454 /// Return the local calculated performance counters 1454 /// Return the local calculated performance counters
@@ -1478,7 +1478,7 @@ namespace Amib.Threading
1478 _shuttingDownEvent = null; 1478 _shuttingDownEvent = null;
1479 } 1479 }
1480 _workerThreads.Clear(); 1480 _workerThreads.Clear();
1481 1481
1482 if (null != _isIdleWaitHandle) 1482 if (null != _isIdleWaitHandle)
1483 { 1483 {
1484 _isIdleWaitHandle.Close(); 1484 _isIdleWaitHandle.Close();
@@ -1507,22 +1507,22 @@ namespace Amib.Threading
1507 /// Get/Set the maximum number of work items that execute cocurrency on the thread pool 1507 /// Get/Set the maximum number of work items that execute cocurrency on the thread pool
1508 /// </summary> 1508 /// </summary>
1509 public override int Concurrency 1509 public override int Concurrency
1510 { 1510 {
1511 get { return MaxThreads; } 1511 get { return MaxThreads; }
1512 set { MaxThreads = value; } 1512 set { MaxThreads = value; }
1513 } 1513 }
1514 1514
1515 /// <summary> 1515 /// <summary>
1516 /// Get the number of work items in the queue. 1516 /// Get the number of work items in the queue.
1517 /// </summary> 1517 /// </summary>
1518 public override int WaitingCallbacks 1518 public override int WaitingCallbacks
1519 { 1519 {
1520 get 1520 get
1521 { 1521 {
1522 ValidateNotDisposed(); 1522 ValidateNotDisposed();
1523 return _workItemsQueue.Count; 1523 return _workItemsQueue.Count;
1524 } 1524 }
1525 } 1525 }
1526 1526
1527 /// <summary> 1527 /// <summary>
1528 /// Get an array with all the state objects of the currently running items. 1528 /// Get an array with all the state objects of the currently running items.
@@ -1542,7 +1542,7 @@ namespace Amib.Threading
1542 get { return _stpStartInfo.AsReadOnly(); } 1542 get { return _stpStartInfo.AsReadOnly(); }
1543 } 1543 }
1544 1544
1545 /// <summary> 1545 /// <summary>
1546 /// Start the thread pool if it was started suspended. 1546 /// Start the thread pool if it was started suspended.
1547 /// If it is already running, this method is ignored. 1547 /// If it is already running, this method is ignored.
1548 /// </summary> 1548 /// </summary>
@@ -1593,7 +1593,7 @@ namespace Amib.Threading
1593 } 1593 }
1594 } 1594 }
1595 1595
1596 /// <summary> 1596 /// <summary>
1597 /// Wait for the thread pool to be idle 1597 /// Wait for the thread pool to be idle
1598 /// </summary> 1598 /// </summary>
1599 public override bool WaitForIdle(int millisecondsTimeout) 1599 public override bool WaitForIdle(int millisecondsTimeout)
@@ -1622,9 +1622,9 @@ namespace Amib.Threading
1622 } 1622 }
1623 } 1623 }
1624 1624
1625 internal override void PreQueueWorkItem() 1625 internal override void PreQueueWorkItem()
1626 { 1626 {
1627 ValidateNotDisposed(); 1627 ValidateNotDisposed();
1628 } 1628 }
1629 1629
1630 #endregion 1630 #endregion
@@ -1676,7 +1676,7 @@ namespace Amib.Threading
1676 ManualResetEvent anActionCompleted = new ManualResetEvent(false); 1676 ManualResetEvent anActionCompleted = new ManualResetEvent(false);
1677 1677
1678 ChoiceIndex choiceIndex = new ChoiceIndex(); 1678 ChoiceIndex choiceIndex = new ChoiceIndex();
1679 1679
1680 int i = 0; 1680 int i = 0;
1681 foreach (Action action in actions) 1681 foreach (Action action in actions)
1682 { 1682 {
@@ -1685,7 +1685,7 @@ namespace Amib.Threading
1685 workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); }); 1685 workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); });
1686 ++i; 1686 ++i;
1687 } 1687 }
1688 workItemsGroup.Start(); 1688 workItemsGroup.Start();
1689 anActionCompleted.WaitOne(); 1689 anActionCompleted.WaitOne();
1690 anActionCompleted.Dispose(); 1690 anActionCompleted.Dispose();
1691 1691
@@ -1698,7 +1698,7 @@ namespace Amib.Threading
1698 /// </summary> 1698 /// </summary>
1699 /// <param name="actions">Actions to execute</param> 1699 /// <param name="actions">Actions to execute</param>
1700 public int Choice(params Action[] actions) 1700 public int Choice(params Action[] actions)
1701 { 1701 {
1702 return Choice((IEnumerable<Action>)actions); 1702 return Choice((IEnumerable<Action>)actions);
1703 } 1703 }
1704 1704
@@ -1732,6 +1732,6 @@ namespace Amib.Threading
1732 Pipe(pipeState, (IEnumerable<Action<T>>)actions); 1732 Pipe(pipeState, (IEnumerable<Action<T>>)actions);
1733 } 1733 }
1734 #endregion 1734 #endregion
1735 } 1735 }
1736 #endregion 1736 #endregion
1737} 1737}