From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- ThirdParty/SmartThreadPool/SmartThreadPool.cs | 1643 +++++++++++++------------ 1 file changed, 824 insertions(+), 819 deletions(-) (limited to 'ThirdParty/SmartThreadPool/SmartThreadPool.cs') diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.cs index 615518e..7cc7fbf 100644 --- a/ThirdParty/SmartThreadPool/SmartThreadPool.cs +++ b/ThirdParty/SmartThreadPool/SmartThreadPool.cs @@ -3,7 +3,7 @@ // Smart Thread Pool // 7 Aug 2004 - Initial release // -// 14 Sep 2004 - Bug fixes +// 14 Sep 2004 - Bug fixes // // 15 Oct 2004 - Added new features // - Work items return result. @@ -18,13 +18,13 @@ // - Added finalizers. // - Changed Exceptions so they are serializable. // - Fixed the bug in one of the SmartThreadPool constructors. -// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. +// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. // The SmartThreadPool.WaitAny() is still limited by the .NET Framework. // - Added PostExecute with options on which cases to call it. // - Added option to dispose of the state objects. // - Added a WaitForIdle() method that waits until the work items queue is empty. // - Added an STPStartInfo class for the initialization of the thread pool. -// - Changed exception handling so if a work item throws an exception it +// - Changed exception handling so if a work item throws an exception it // is rethrown at GetResult(), rather then firing an UnhandledException event. // Note that PostExecute exception are always ignored. // @@ -32,10 +32,10 @@ // - Fixed lost of work items bug // // 3 Jul 2005: Changes. -// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. +// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. // // 16 Aug 2005: Changes. -// - Fixed bug where the InUseThreads becomes negative when canceling work items. +// - Fixed bug where the InUseThreads becomes negative when canceling work items. // // 31 Jan 2006 - Changes: // - Added work items priority @@ -45,7 +45,7 @@ // - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array // it returns true rather then throwing an exception. // - Added option to start the STP and the WIG as suspended -// - Exception behavior changed, the real exception is returned by an +// - Exception behavior changed, the real exception is returned by an // inner exception // - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) // - Added performance counters @@ -54,17 +54,17 @@ // 13 Feb 2006 - Changes: // - Added a call to the dispose of the Performance Counter so // their won't be a Performance Counter leak. -// - Added exception catch in case the Performance Counters cannot +// - Added exception catch in case the Performance Counters cannot // be created. // // 17 May 2008 - Changes: // - Changed the dispose behavior and removed the Finalizers. // - Enabled the change of the MaxThreads and MinThreads at run time. -// - Enabled the change of the Concurrency of a IWorkItemsGroup at run -// time If the IWorkItemsGroup is a SmartThreadPool then the Concurrency -// refers to the MaxThreads. +// - Enabled the change of the Concurrency of a IWorkItemsGroup at run +// time If the IWorkItemsGroup is a SmartThreadPool then the Concurrency +// refers to the MaxThreads. // - Improved the cancel behavior. -// - Added events for thread creation and termination. +// - Added events for thread creation and termination. // - Fixed the HttpContext context capture. // - Changed internal collections so they use generic collections // - Added IsIdle flag to the SmartThreadPool and IWorkItemsGroup @@ -83,7 +83,7 @@ // // 20 August 2012 - Changes: // - Added set name to threads -// - Fixed the WorkItemsQueue.Dequeue. +// - Fixed the WorkItemsQueue.Dequeue. // Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... } // - Fixed SmartThreadPool.Pipe // - Added IsBackground option to threads @@ -92,7 +92,7 @@ // // 24 August 2012 - Changes: // - Enabled cancel abort after cancel. See: http://smartthreadpool.codeplex.com/discussions/345937 by alecswan -// - Added option to set MaxStackSize of threads +// - Added option to set MaxStackSize of threads #endregion @@ -108,77 +108,77 @@ using Amib.Threading.Internal; namespace Amib.Threading { - #region SmartThreadPool class - /// - /// Smart thread pool class. - /// - public partial class SmartThreadPool : WorkItemsGroupBase, IDisposable - { - #region Public Default Constants - - /// - /// Default minimum number of threads the thread pool contains. (0) - /// - public const int DefaultMinWorkerThreads = 0; - - /// - /// Default maximum number of threads the thread pool contains. (25) - /// - public const int DefaultMaxWorkerThreads = 25; - - /// - /// Default idle timeout in milliseconds. (One minute) - /// - public const int DefaultIdleTimeout = 60*1000; // One minute - - /// - /// Indicate to copy the security context of the caller and then use it in the call. (false) - /// - public const bool DefaultUseCallerCallContext = false; - - /// - /// Indicate to copy the HTTP context of the caller and then use it in the call. (false) - /// - public const bool DefaultUseCallerHttpContext = false; - - /// - /// Indicate to dispose of the state objects if they support the IDispose interface. (false) - /// - public const bool DefaultDisposeOfStateObjects = false; - - /// + #region SmartThreadPool class + /// + /// Smart thread pool class. + /// + public partial class SmartThreadPool : WorkItemsGroupBase, IDisposable + { + #region Public Default Constants + + /// + /// Default minimum number of threads the thread pool contains. (0) + /// + public const int DefaultMinWorkerThreads = 0; + + /// + /// Default maximum number of threads the thread pool contains. (25) + /// + public const int DefaultMaxWorkerThreads = 25; + + /// + /// Default idle timeout in milliseconds. (One minute) + /// + public const int DefaultIdleTimeout = 60*1000; // One minute + + /// + /// Indicate to copy the security context of the caller and then use it in the call. (false) + /// + public const bool DefaultUseCallerCallContext = false; + + /// + /// Indicate to copy the HTTP context of the caller and then use it in the call. (false) + /// + public const bool DefaultUseCallerHttpContext = false; + + /// + /// Indicate to dispose of the state objects if they support the IDispose interface. (false) + /// + public const bool DefaultDisposeOfStateObjects = false; + + /// /// The default option to run the post execute (CallToPostExecute.Always) - /// - public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always; + /// + public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always; - /// - /// The default post execute method to run. (None) - /// When null it means not to call it. - /// - public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback; + /// + /// The default post execute method to run. (None) + /// When null it means not to call it. + /// + public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback; - /// + /// /// The default work item priority (WorkItemPriority.Normal) - /// - public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal; + /// + public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal; - /// - /// The default is to work on work items as soon as they arrive - /// and not to wait for the start. (false) - /// - public const bool DefaultStartSuspended = false; + /// + /// The default is to work on work items as soon as they arrive + /// and not to wait for the start. (false) + /// + public const bool DefaultStartSuspended = false; - /// + /// /// The default name to use for the performance counters instance. (null) - /// - public static readonly string DefaultPerformanceCounterInstanceName; + /// + public static readonly string DefaultPerformanceCounterInstanceName; #if !(WINDOWS_PHONE) - /// + /// /// The default thread priority (ThreadPriority.Normal) - /// - public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; + /// + public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; #endif /// /// The default thread pool name. (SmartThreadPool) @@ -203,37 +203,37 @@ namespace Amib.Threading #if !(_SILVERLIGHT) && !(WINDOWS_PHONE) /// - /// The default apartment state of a thread in the thread pool. - /// The default is ApartmentState.Unknown which means the STP will not + /// The default apartment state of a thread in the thread pool. + /// The default is ApartmentState.Unknown which means the STP will not /// set the apartment of the thread. It will use the .NET default. /// public const ApartmentState DefaultApartmentState = ApartmentState.Unknown; #endif - #endregion + #endregion #region Member Variables - /// - /// Dictionary of all the threads in the thread pool. - /// + /// + /// Dictionary of all the threads in the thread pool. + /// private readonly SynchronizedDictionary _workerThreads = new SynchronizedDictionary(); - /// - /// Queue of work items. - /// - private readonly WorkItemsQueue _workItemsQueue = new WorkItemsQueue(); + /// + /// Queue of work items. + /// + private readonly WorkItemsQueue _workItemsQueue = new WorkItemsQueue(); - /// - /// Count the work items handled. - /// Used by the performance counter. - /// - private int _workItemsProcessed; + /// + /// Count the work items handled. + /// Used by the performance counter. + /// + private int _workItemsProcessed; - /// - /// Number of threads that currently work (not idle). - /// - private int _inUseWorkerThreads; + /// + /// Number of threads that currently work (not idle). + /// + private int _inUseWorkerThreads; /// /// Stores a copy of the original STPStartInfo. @@ -241,51 +241,51 @@ namespace Amib.Threading /// private STPStartInfo _stpStartInfo; - /// - /// Total number of work items that are stored in the work items queue - /// plus the work items that the threads in the pool are working on. - /// - private int _currentWorkItemsCount; + /// + /// Total number of work items that are stored in the work items queue + /// plus the work items that the threads in the pool are working on. + /// + private int _currentWorkItemsCount; - /// - /// Signaled when the thread pool is idle, i.e. no thread is busy - /// and the work items queue is empty - /// - //private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); - private ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); + /// + /// Signaled when the thread pool is idle, i.e. no thread is busy + /// and the work items queue is empty + /// + //private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); + private ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); - /// - /// An event to signal all the threads to quit immediately. - /// - //private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false); - private ManualResetEvent _shuttingDownEvent = EventWaitHandleFactory.CreateManualResetEvent(false); + /// + /// An event to signal all the threads to quit immediately. + /// + //private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false); + private ManualResetEvent _shuttingDownEvent = EventWaitHandleFactory.CreateManualResetEvent(false); /// /// A flag to indicate if the Smart Thread Pool is now suspended. /// private bool _isSuspended; - /// - /// A flag to indicate the threads to quit. - /// - private bool _shutdown; - - /// - /// Counts the threads created in the pool. - /// It is used to name the threads. - /// - private int _threadCounter; - - /// - /// Indicate that the SmartThreadPool has been disposed - /// - private bool _isDisposed; - - /// - /// Holds all the WorkItemsGroup instaces that have at least one - /// work item int the SmartThreadPool - /// This variable is used in case of Shutdown - /// + /// + /// A flag to indicate the threads to quit. + /// + private bool _shutdown; + + /// + /// Counts the threads created in the pool. + /// It is used to name the threads. + /// + private int _threadCounter; + + /// + /// Indicate that the SmartThreadPool has been disposed + /// + private bool _isDisposed; + + /// + /// Holds all the WorkItemsGroup instaces that have at least one + /// work item int the SmartThreadPool + /// This variable is used in case of Shutdown + /// private readonly SynchronizedDictionary _workItemsGroups = new SynchronizedDictionary(); /// @@ -305,7 +305,7 @@ namespace Amib.Threading private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance; -#if (WINDOWS_PHONE) +#if (WINDOWS_PHONE) private static readonly Dictionary _threadEntries = new Dictionary(); #elif (_WINDOWS_CE) private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot(); @@ -316,13 +316,13 @@ namespace Amib.Threading #endif /// - /// An event to call after a thread is created, but before + /// An event to call after a thread is created, but before /// it's first use. /// private event ThreadInitializationHandler _onThreadInitialization; /// - /// An event to call when a thread is about to exit, after + /// An event to call when a thread is about to exit, after /// it is no longer belong to the pool. /// private event ThreadTerminationHandler _onThreadTermination; @@ -332,7 +332,7 @@ namespace Amib.Threading #region Per thread properties /// - /// A reference to the current work item a thread from the thread pool + /// A reference to the current work item a thread from the thread pool /// is executing. /// internal static ThreadEntry CurrentThreadEntry @@ -383,78 +383,78 @@ namespace Amib.Threading #region Construction and Finalization /// - /// Constructor - /// - public SmartThreadPool() - { + /// Constructor + /// + public SmartThreadPool() + { _stpStartInfo = new STPStartInfo(); Initialize(); - } - - /// - /// Constructor - /// - /// Idle timeout in milliseconds - public SmartThreadPool(int idleTimeout) - { + } + + /// + /// Constructor + /// + /// Idle timeout in milliseconds + public SmartThreadPool(int idleTimeout) + { _stpStartInfo = new STPStartInfo { IdleTimeout = idleTimeout, }; - Initialize(); - } - - /// - /// Constructor - /// - /// Idle timeout in milliseconds - /// Upper limit of threads in the pool - public SmartThreadPool( - int idleTimeout, - int maxWorkerThreads) - { + Initialize(); + } + + /// + /// Constructor + /// + /// Idle timeout in milliseconds + /// Upper limit of threads in the pool + public SmartThreadPool( + int idleTimeout, + int maxWorkerThreads) + { _stpStartInfo = new STPStartInfo { IdleTimeout = idleTimeout, MaxWorkerThreads = maxWorkerThreads, }; - Initialize(); - } - - /// - /// Constructor - /// - /// Idle timeout in milliseconds - /// Upper limit of threads in the pool - /// Lower limit of threads in the pool - public SmartThreadPool( - int idleTimeout, - int maxWorkerThreads, - int minWorkerThreads) - { + Initialize(); + } + + /// + /// Constructor + /// + /// Idle timeout in milliseconds + /// Upper limit of threads in the pool + /// Lower limit of threads in the pool + public SmartThreadPool( + int idleTimeout, + int maxWorkerThreads, + int minWorkerThreads) + { _stpStartInfo = new STPStartInfo { IdleTimeout = idleTimeout, MaxWorkerThreads = maxWorkerThreads, MinWorkerThreads = minWorkerThreads, }; - Initialize(); - } + Initialize(); + } /// /// Constructor /// /// A SmartThreadPool configuration that overrides the default behavior - public SmartThreadPool(STPStartInfo stpStartInfo) - { - _stpStartInfo = new STPStartInfo(stpStartInfo); - Initialize(); - } - - private void Initialize() - { + public SmartThreadPool(STPStartInfo stpStartInfo) + { + _stpStartInfo = new STPStartInfo(stpStartInfo); + Initialize(); + } + + private void Initialize() + { Name = _stpStartInfo.ThreadPoolName; - ValidateSTPStartInfo(); + ValidateSTPStartInfo(); // _stpStartInfoRW stores a read/write copy of the STPStartInfo. // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten @@ -462,8 +462,8 @@ namespace Amib.Threading _isSuspended = _stpStartInfo.StartSuspended; #if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE) - if (null != _stpStartInfo.PerformanceCounterInstanceName) - { + if (null != _stpStartInfo.PerformanceCounterInstanceName) + { throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters"); } #else @@ -486,110 +486,110 @@ namespace Amib.Threading _localPCs = new LocalSTPInstancePerformanceCounters(); } - // If the STP is not started suspended then start the threads. + // If the STP is not started suspended then start the threads. if (!_isSuspended) { StartOptimalNumberOfThreads(); } - } + } - private void StartOptimalNumberOfThreads() - { - int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads); + private void StartOptimalNumberOfThreads() + { + int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads); threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads); threadsCount -= _workerThreads.Count; if (threadsCount > 0) { StartThreads(threadsCount); } - } + } - private void ValidateSTPStartInfo() - { + private void ValidateSTPStartInfo() + { if (_stpStartInfo.MinWorkerThreads < 0) - { - throw new ArgumentOutOfRangeException( - "MinWorkerThreads", "MinWorkerThreads cannot be negative"); - } + { + throw new ArgumentOutOfRangeException( + "MinWorkerThreads", "MinWorkerThreads cannot be negative"); + } if (_stpStartInfo.MaxWorkerThreads <= 0) - { - throw new ArgumentOutOfRangeException( - "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero"); - } + { + throw new ArgumentOutOfRangeException( + "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero"); + } if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads) - { - throw new ArgumentOutOfRangeException( - "MinWorkerThreads, maxWorkerThreads", - "MaxWorkerThreads must be greater or equal to MinWorkerThreads"); - } - } - - private static void ValidateCallback(Delegate callback) - { - if(callback.GetInvocationList().Length > 1) - { - throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); - } - } - - #endregion - - #region Thread Processing - - /// - /// Waits on the queue for a work item, shutdown, or timeout. - /// - /// - /// Returns the WaitingCallback or null in case of timeout or shutdown. - /// - private WorkItem Dequeue() - { - WorkItem workItem = + { + throw new ArgumentOutOfRangeException( + "MinWorkerThreads, maxWorkerThreads", + "MaxWorkerThreads must be greater or equal to MinWorkerThreads"); + } + } + + private static void ValidateCallback(Delegate callback) + { + if(callback.GetInvocationList().Length > 1) + { + throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); + } + } + + #endregion + + #region Thread Processing + + /// + /// Waits on the queue for a work item, shutdown, or timeout. + /// + /// + /// Returns the WaitingCallback or null in case of timeout or shutdown. + /// + private WorkItem Dequeue() + { + WorkItem workItem = _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); - return workItem; - } + return workItem; + } - /// - /// Put a new work item in the queue - /// - /// A work item to queue - internal override void Enqueue(WorkItem workItem) - { - // Make sure the workItem is not null - Debug.Assert(null != workItem); + /// + /// Put a new work item in the queue + /// + /// A work item to queue + internal override void Enqueue(WorkItem workItem) + { + // Make sure the workItem is not null + Debug.Assert(null != workItem); - IncrementWorkItemsCount(); + IncrementWorkItemsCount(); workItem.CanceledSmartThreadPool = _canceledSmartThreadPool; - _workItemsQueue.EnqueueWorkItem(workItem); - workItem.WorkItemIsQueued(); - - // If all the threads are busy then try to create a new one - if (_currentWorkItemsCount > _workerThreads.Count) - { - StartThreads(1); - } - } - - private void IncrementWorkItemsCount() - { - _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + _workItemsQueue.EnqueueWorkItem(workItem); + workItem.WorkItemIsQueued(); + + // If all the threads are busy then try to create a new one + if (_currentWorkItemsCount > _workerThreads.Count) + { + StartThreads(1); + } + } + + private void IncrementWorkItemsCount() + { + _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); - int count = Interlocked.Increment(ref _currentWorkItemsCount); - //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); - if (count == 1) - { + int count = Interlocked.Increment(ref _currentWorkItemsCount); + //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); + if (count == 1) + { IsIdle = false; _isIdleWaitHandle.Reset(); - } - } + } + } - private void DecrementWorkItemsCount() - { + private void DecrementWorkItemsCount() + { int count = Interlocked.Decrement(ref _currentWorkItemsCount); //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); if (count == 0) @@ -602,81 +602,81 @@ namespace Amib.Threading if (!_shutdown) { - // The counter counts even if the work item was cancelled - _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + // The counter counts even if the work item was cancelled + _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); } - } - - internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) - { - _workItemsGroups[workItemsGroup] = workItemsGroup; - } - - internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) - { - if (_workItemsGroups.Contains(workItemsGroup)) - { - _workItemsGroups.Remove(workItemsGroup); - } - } - - /// - /// Inform that the current thread is about to quit or quiting. - /// The same thread may call this method more than once. - /// - private void InformCompleted() - { - // There is no need to lock the two methods together - // since only the current thread removes itself - // and the _workerThreads is a synchronized dictionary - if (_workerThreads.Contains(Thread.CurrentThread)) - { - _workerThreads.Remove(Thread.CurrentThread); - _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + } + + internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) + { + _workItemsGroups[workItemsGroup] = workItemsGroup; + } + + internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) + { + if (_workItemsGroups.Contains(workItemsGroup)) + { + _workItemsGroups.Remove(workItemsGroup); + } + } + + /// + /// Inform that the current thread is about to quit or quiting. + /// The same thread may call this method more than once. + /// + private void InformCompleted() + { + // There is no need to lock the two methods together + // since only the current thread removes itself + // and the _workerThreads is a synchronized dictionary + if (_workerThreads.Contains(Thread.CurrentThread)) + { + _workerThreads.Remove(Thread.CurrentThread); + _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); - } - } - - /// - /// Starts new threads - /// - /// The number of threads to start - private void StartThreads(int threadsCount) - { + } + } + + /// + /// Starts new threads + /// + /// The number of threads to start + private void StartThreads(int threadsCount) + { if (_isSuspended) - { - return; - } - - lock(_workerThreads.SyncRoot) - { - // Don't start threads on shut down - if (_shutdown) - { - return; - } - - for(int i = 0; i < threadsCount; ++i) - { - // Don't create more threads then the upper limit + { + return; + } + + lock(_workerThreads.SyncRoot) + { + // Don't start threads on shut down + if (_shutdown) + { + return; + } + + for(int i = 0; i < threadsCount; ++i) + { + // Don't create more threads then the upper limit if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) - { - return; - } + { + return; + } // Create a new thread #if (_SILVERLIGHT) || (WINDOWS_PHONE) - Thread workerThread = new Thread(ProcessQueuedItems); + Thread workerThread = new Thread(ProcessQueuedItems); #else Thread workerThread = _stpStartInfo.MaxStackSize.HasValue ? new Thread(ProcessQueuedItems, _stpStartInfo.MaxStackSize.Value) : new Thread(ProcessQueuedItems); #endif - // Configure the new thread and start it + // Configure the new thread and start it workerThread.IsBackground = _stpStartInfo.AreThreadsBackground; #if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE) @@ -689,39 +689,40 @@ namespace Amib.Threading #if !(_SILVERLIGHT) && !(WINDOWS_PHONE) workerThread.Priority = _stpStartInfo.ThreadPriority; #endif - workerThread.Start(); workerThread.Name = string.Format("STP:{0}:{1}", Name, _threadCounter); - ++_threadCounter; + workerThread.Start(); + + ++_threadCounter; // Add it to the dictionary and update its creation time. _workerThreads[workerThread] = new ThreadEntry(this); - _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); - } - } - } - - /// - /// A worker thread method that processes work items from the work items queue. - /// - private void ProcessQueuedItems() - { + } + } + } + + /// + /// A worker thread method that processes work items from the work items queue. + /// + private void ProcessQueuedItems() + { // Keep the entry of the dictionary as thread's variable to avoid the synchronization locks // of the dictionary. CurrentThreadEntry = _workerThreads[Thread.CurrentThread]; FireOnThreadInitialization(); - try - { - bool bInUseWorkerThreadsWasIncremented = false; + try + { + bool bInUseWorkerThreadsWasIncremented = false; - // Process until shutdown. - while(!_shutdown) - { - // Update the last time this thread was seen alive. - // It's good for debugging. + // Process until shutdown. + while(!_shutdown) + { + // Update the last time this thread was seen alive. + // It's good for debugging. CurrentThreadEntry.IAmAlive(); // The following block handles the when the MaxWorkerThreads has been @@ -743,166 +744,166 @@ namespace Amib.Threading } } - // Wait for a work item, shutdown, or timeout - WorkItem workItem = Dequeue(); + // Wait for a work item, shutdown, or timeout + WorkItem workItem = Dequeue(); - // Update the last time this thread was seen alive. - // It's good for debugging. + // Update the last time this thread was seen alive. + // It's good for debugging. CurrentThreadEntry.IAmAlive(); - // On timeout or shut down. - if (null == workItem) - { - // Double lock for quit. + // On timeout or shut down. + if (null == workItem) + { + // Double lock for quit. if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) - { - lock(_workerThreads.SyncRoot) - { + { + lock(_workerThreads.SyncRoot) + { if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) - { - // Inform that the thread is quiting and then quit. - // This method must be called within this lock or else - // more threads will quit and the thread pool will go - // below the lower limit. - InformCompleted(); - break; - } - } - } - } - - // If we didn't quit then skip to the next iteration. - if (null == workItem) - { - continue; - } - - try - { - // Initialize the value to false - bInUseWorkerThreadsWasIncremented = false; + { + // Inform that the thread is quiting and then quit. + // This method must be called within this lock or else + // more threads will quit and the thread pool will go + // below the lower limit. + InformCompleted(); + break; + } + } + } + } + + // If we didn't quit then skip to the next iteration. + if (null == workItem) + { + continue; + } + + try + { + // Initialize the value to false + bInUseWorkerThreadsWasIncremented = false; // Set the Current Work Item of the thread. - // Store the Current Work Item before the workItem.StartingWorkItem() is called, - // so WorkItem.Cancel can work when the work item is between InQueue and InProgress + // Store the Current Work Item before the workItem.StartingWorkItem() is called, + // so WorkItem.Cancel can work when the work item is between InQueue and InProgress // states. - // If the work item has been cancelled BEFORE the workItem.StartingWorkItem() + // If the work item has been cancelled BEFORE the workItem.StartingWorkItem() // (work item is in InQueue state) then workItem.StartingWorkItem() will return false. // If the work item has been cancelled AFTER the workItem.StartingWorkItem() then // (work item is in InProgress state) then the thread will be aborted CurrentThreadEntry.CurrentWorkItem = workItem; - // Change the state of the work item to 'in progress' if possible. - // We do it here so if the work item has been canceled we won't - // increment the _inUseWorkerThreads. - // The cancel mechanism doesn't delete items from the queue, - // it marks the work item as canceled, and when the work item - // is dequeued, we just skip it. - // If the post execute of work item is set to always or to - // call when the work item is canceled then the StartingWorkItem() - // will return true, so the post execute can run. - if (!workItem.StartingWorkItem()) - { - continue; - } - - // Execute the callback. Make sure to accurately - // record how many callbacks are currently executing. - int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads); - _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + // Change the state of the work item to 'in progress' if possible. + // We do it here so if the work item has been canceled we won't + // increment the _inUseWorkerThreads. + // The cancel mechanism doesn't delete items from the queue, + // it marks the work item as canceled, and when the work item + // is dequeued, we just skip it. + // If the post execute of work item is set to always or to + // call when the work item is canceled then the StartingWorkItem() + // will return true, so the post execute can run. + if (!workItem.StartingWorkItem()) + { + continue; + } + + // Execute the callback. Make sure to accurately + // record how many callbacks are currently executing. + int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads); + _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); - // Mark that the _inUseWorkerThreads incremented, so in the finally{} - // statement we will decrement it correctly. - bInUseWorkerThreadsWasIncremented = true; + // Mark that the _inUseWorkerThreads incremented, so in the finally{} + // statement we will decrement it correctly. + bInUseWorkerThreadsWasIncremented = true; workItem.FireWorkItemStarted(); - ExecuteWorkItem(workItem); - } - catch(Exception ex) - { + ExecuteWorkItem(workItem); + } + catch(Exception ex) + { ex.GetHashCode(); - // Do nothing - } - finally - { - workItem.DisposeOfState(); - - // Set the CurrentWorkItem to null, since we - // no longer run user's code. + // Do nothing + } + finally + { + workItem.DisposeOfState(); + + // Set the CurrentWorkItem to null, since we + // no longer run user's code. CurrentThreadEntry.CurrentWorkItem = null; - // Decrement the _inUseWorkerThreads only if we had - // incremented it. Note the cancelled work items don't - // increment _inUseWorkerThreads. - if (bInUseWorkerThreadsWasIncremented) - { - int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads); - _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + // Decrement the _inUseWorkerThreads only if we had + // incremented it. Note the cancelled work items don't + // increment _inUseWorkerThreads. + if (bInUseWorkerThreadsWasIncremented) + { + int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads); + _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); - } - - // Notify that the work item has been completed. - // WorkItemsGroup may enqueue their next work item. - workItem.FireWorkItemCompleted(); - - // Decrement the number of work items here so the idle - // ManualResetEvent won't fluctuate. - DecrementWorkItemsCount(); - } - } - } - catch(ThreadAbortException tae) - { + } + + // Notify that the work item has been completed. + // WorkItemsGroup may enqueue their next work item. + workItem.FireWorkItemCompleted(); + + // Decrement the number of work items here so the idle + // ManualResetEvent won't fluctuate. + DecrementWorkItemsCount(); + } + } + } + catch(ThreadAbortException tae) + { tae.GetHashCode(); // Handle the abort exception gracfully. #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - Thread.ResetAbort(); + Thread.ResetAbort(); #endif } - catch(Exception e) - { - Debug.Assert(null != e); - } - finally - { - InformCompleted(); + catch(Exception e) + { + Debug.Assert(null != e); + } + finally + { + InformCompleted(); FireOnThreadTermination(); - } - } + } + } - private void ExecuteWorkItem(WorkItem workItem) - { - _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); + private void ExecuteWorkItem(WorkItem workItem) + { + _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); - try - { - workItem.Execute(); - } - finally - { - _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); + try + { + workItem.Execute(); + } + finally + { + _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); - } - } + } + } - #endregion + #endregion - #region Public Methods + #region Public Methods - private void ValidateWaitForIdle() - { + private void ValidateWaitForIdle() + { if (null != CurrentThreadEntry && CurrentThreadEntry.AssociatedSmartThreadPool == this) - { - throw new NotSupportedException( - "WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); - } - } - - internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup) - { + { + throw new NotSupportedException( + "WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); + } + } + + internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup) + { if (null == CurrentThreadEntry) { return; @@ -910,334 +911,334 @@ namespace Amib.Threading WorkItem workItem = CurrentThreadEntry.CurrentWorkItem; ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem); - if ((null != workItemsGroup) && + if ((null != workItemsGroup) && (null != workItem) && CurrentThreadEntry.CurrentWorkItem.WasQueuedBy(workItemsGroup)) - { - throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem) - { - if ((null != workItemsGroup) && - (null != workItem) && - workItem.WasQueuedBy(workItemsGroup)) - { - throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); - } - } - - /// - /// Force the SmartThreadPool to shutdown - /// - public void Shutdown() - { - Shutdown(true, 0); - } + { + throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem) + { + if ((null != workItemsGroup) && + (null != workItem) && + workItem.WasQueuedBy(workItemsGroup)) + { + throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); + } + } + + /// + /// Force the SmartThreadPool to shutdown + /// + public void Shutdown() + { + Shutdown(true, 0); + } /// /// Force the SmartThreadPool to shutdown with timeout /// public void Shutdown(bool forceAbort, TimeSpan timeout) - { - Shutdown(forceAbort, (int)timeout.TotalMilliseconds); - } + { + Shutdown(forceAbort, (int)timeout.TotalMilliseconds); + } - /// - /// Empties the queue of work items and abort the threads in the pool. - /// - public void Shutdown(bool forceAbort, int millisecondsTimeout) - { - ValidateNotDisposed(); + /// + /// Empties the queue of work items and abort the threads in the pool. + /// + public void Shutdown(bool forceAbort, int millisecondsTimeout) + { + ValidateNotDisposed(); - ISTPInstancePerformanceCounters pcs = _windowsPCs; + ISTPInstancePerformanceCounters pcs = _windowsPCs; - if (NullSTPInstancePerformanceCounters.Instance != _windowsPCs) - { - // Set the _pcs to "null" to stop updating the performance - // counters - _windowsPCs = NullSTPInstancePerformanceCounters.Instance; + if (NullSTPInstancePerformanceCounters.Instance != _windowsPCs) + { + // Set the _pcs to "null" to stop updating the performance + // counters + _windowsPCs = NullSTPInstancePerformanceCounters.Instance; pcs.Dispose(); - } + } - Thread [] threads; - lock(_workerThreads.SyncRoot) - { - // Shutdown the work items queue - _workItemsQueue.Dispose(); + Thread [] threads; + lock(_workerThreads.SyncRoot) + { + // Shutdown the work items queue + _workItemsQueue.Dispose(); - // Signal the threads to exit - _shutdown = true; - _shuttingDownEvent.Set(); + // Signal the threads to exit + _shutdown = true; + _shuttingDownEvent.Set(); - // Make a copy of the threads' references in the pool - threads = new Thread [_workerThreads.Count]; - _workerThreads.Keys.CopyTo(threads, 0); - } + // Make a copy of the threads' references in the pool + threads = new Thread [_workerThreads.Count]; + _workerThreads.Keys.CopyTo(threads, 0); + } - int millisecondsLeft = millisecondsTimeout; + int millisecondsLeft = millisecondsTimeout; Stopwatch stopwatch = Stopwatch.StartNew(); //DateTime start = DateTime.UtcNow; - bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); - bool timeout = false; - - // Each iteration we update the time left for the timeout. - foreach(Thread thread in threads) - { - // Join don't work with negative numbers - if (!waitInfinitely && (millisecondsLeft < 0)) - { - timeout = true; - break; - } - - // Wait for the thread to terminate - bool success = thread.Join(millisecondsLeft); - if(!success) - { - timeout = true; - break; - } - - if(!waitInfinitely) - { - // Update the time left to wait + bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); + bool timeout = false; + + // Each iteration we update the time left for the timeout. + foreach(Thread thread in threads) + { + // Join don't work with negative numbers + if (!waitInfinitely && (millisecondsLeft < 0)) + { + timeout = true; + break; + } + + // Wait for the thread to terminate + bool success = thread.Join(millisecondsLeft); + if(!success) + { + timeout = true; + break; + } + + if(!waitInfinitely) + { + // Update the time left to wait //TimeSpan ts = DateTime.UtcNow - start; millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds; - } - } - - if (timeout && forceAbort) - { - // Abort the threads in the pool - foreach(Thread thread in threads) - { - - if ((thread != null) + } + } + + if (timeout && forceAbort) + { + // Abort the threads in the pool + foreach(Thread thread in threads) + { + + if ((thread != null) #if !(_WINDOWS_CE) && thread.IsAlive -#endif +#endif ) - { - try - { + { + try + { thread.Abort(); // Shutdown - } - catch(SecurityException e) - { + } + catch(SecurityException e) + { e.GetHashCode(); - } - catch(ThreadStateException ex) - { + } + catch(ThreadStateException ex) + { ex.GetHashCode(); - // In case the thread has been terminated - // after the check if it is alive. - } - } - } - } - } - - /// - /// Wait for all work items to complete - /// + // In case the thread has been terminated + // after the check if it is alive. + } + } + } + } + } + + /// + /// Wait for all work items to complete + /// /// Array of work item result objects - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWaitableResult [] waitableResults) - { + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult [] waitableResults) + { return WaitAll(waitableResults, Timeout.Infinite, true); - } + } - /// - /// Wait for all work items to complete - /// + /// + /// Wait for all work items to complete + /// /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWaitableResult [] waitableResults, - TimeSpan timeout, - bool exitContext) - { + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult [] waitableResults, + TimeSpan timeout, + bool exitContext) + { return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext); - } + } - /// - /// Wait for all work items to complete - /// + /// + /// Wait for all work items to complete + /// /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWaitableResult[] waitableResults, - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult[] waitableResults, + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } + } - /// - /// Wait for all work items to complete - /// + /// + /// Wait for all work items to complete + /// /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWaitableResult [] waitableResults, - int millisecondsTimeout, - bool exitContext) - { + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult [] waitableResults, + int millisecondsTimeout, + bool exitContext) + { return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null); - } + } - /// - /// Wait for all work items to complete - /// + /// + /// Wait for all work items to complete + /// /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWaitableResult[] waitableResults, - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult[] waitableResults, + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); - } + } - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// /// Array of work item result objects - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled. - /// - public static int WaitAny( - IWaitableResult [] waitableResults) - { + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled. + /// + public static int WaitAny( + IWaitableResult [] waitableResults) + { return WaitAny(waitableResults, Timeout.Infinite, true); - } + } - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// 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. - /// - public static int WaitAny( + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// 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. + /// + public static int WaitAny( IWaitableResult[] waitableResults, - TimeSpan timeout, - bool exitContext) - { + TimeSpan timeout, + bool exitContext) + { return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext); - } + } - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// 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. - /// - public static int WaitAny( - IWaitableResult [] waitableResults, - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// 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. + /// + public static int WaitAny( + IWaitableResult [] waitableResults, + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } + } - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// 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. - /// - public static int WaitAny( - IWaitableResult [] waitableResults, - int millisecondsTimeout, - bool exitContext) - { + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// 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. + /// + public static int WaitAny( + IWaitableResult [] waitableResults, + int millisecondsTimeout, + bool exitContext) + { return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null); - } + } - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// 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. - /// - public static int WaitAny( - IWaitableResult [] waitableResults, - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// 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. + /// + public static int WaitAny( + IWaitableResult [] waitableResults, + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); - } + } /// /// Creates a new WorkItemsGroup. /// /// The number of work items that can be run concurrently /// A reference to the WorkItemsGroup - public IWorkItemsGroup CreateWorkItemsGroup(int concurrency) - { + public IWorkItemsGroup CreateWorkItemsGroup(int concurrency) + { IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo); - return workItemsGroup; - } + return workItemsGroup; + } /// /// Creates a new WorkItemsGroup. @@ -1245,11 +1246,11 @@ namespace Amib.Threading /// The number of work items that can be run concurrently /// A WorkItemsGroup configuration that overrides the default behavior /// A reference to the WorkItemsGroup - public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo) - { - IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo); - return workItemsGroup; - } + public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo) + { + IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo); + return workItemsGroup; + } #region Fire Thread's Events @@ -1330,22 +1331,22 @@ namespace Amib.Threading } } - - #endregion - #region Properties + #endregion - /// - /// Get/Set the lower limit of threads in the pool. - /// - public int MinThreads - { - get - { - ValidateNotDisposed(); - return _stpStartInfo.MinWorkerThreads; - } + #region Properties + + /// + /// Get/Set the lower limit of threads in the pool. + /// + public int MinThreads + { + get + { + ValidateNotDisposed(); + return _stpStartInfo.MinWorkerThreads; + } set { Debug.Assert(value >= 0); @@ -1357,21 +1358,21 @@ namespace Amib.Threading _stpStartInfo.MinWorkerThreads = value; StartOptimalNumberOfThreads(); } - } - - /// - /// Get/Set the upper limit of threads in the pool. - /// - public int MaxThreads - { - get - { - ValidateNotDisposed(); - return _stpStartInfo.MaxWorkerThreads; - } - - set - { + } + + /// + /// Get/Set the upper limit of threads in the pool. + /// + public int MaxThreads + { + get + { + ValidateNotDisposed(); + return _stpStartInfo.MaxWorkerThreads; + } + + set + { Debug.Assert(value > 0); Debug.Assert(value >= _stpStartInfo.MinWorkerThreads); if (_stpStartInfo.MinWorkerThreads > value) @@ -1380,32 +1381,32 @@ namespace Amib.Threading } _stpStartInfo.MaxWorkerThreads = value; StartOptimalNumberOfThreads(); - } - } - /// - /// Get the number of threads in the thread pool. - /// Should be between the lower and the upper limits. - /// - public int ActiveThreads - { - get - { - ValidateNotDisposed(); - return _workerThreads.Count; - } - } - - /// - /// Get the number of busy (not idle) threads in the thread pool. - /// - public int InUseThreads - { - get - { - ValidateNotDisposed(); - return _inUseWorkerThreads; - } - } + } + } + /// + /// Get the number of threads in the thread pool. + /// Should be between the lower and the upper limits. + /// + public int ActiveThreads + { + get + { + ValidateNotDisposed(); + return _workerThreads.Count; + } + } + + /// + /// Get the number of busy (not idle) threads in the thread pool. + /// + public int InUseThreads + { + get + { + ValidateNotDisposed(); + return _inUseWorkerThreads; + } + } /// /// Returns true if the current running work item has been cancelled. @@ -1419,8 +1420,8 @@ namespace Amib.Threading { return CurrentThreadEntry.CurrentWorkItem.IsCanceled; } - } - + } + /// /// Checks if the work item has been cancelled, and if yes then abort the thread. /// Can be used with Cancel and timeout @@ -1438,16 +1439,16 @@ namespace Amib.Threading /// public STPStartInfo STPStartInfo { - get + get { - return _stpStartInfo.AsReadOnly(); + return _stpStartInfo.AsReadOnly(); } } - public bool IsShuttingdown - { + public bool IsShuttingdown + { get { return _shutdown; } - } + } /// /// Return the local calculated performance counters @@ -1477,13 +1478,16 @@ namespace Amib.Threading _shuttingDownEvent = null; } _workerThreads.Clear(); - + if (null != _isIdleWaitHandle) { _isIdleWaitHandle.Close(); _isIdleWaitHandle = null; } + if (_stpStartInfo.EnableLocalPerformanceCounters) + _localPCs.Dispose(); + _isDisposed = true; } } @@ -1503,22 +1507,22 @@ namespace Amib.Threading /// Get/Set the maximum number of work items that execute cocurrency on the thread pool /// public override int Concurrency - { - get { return MaxThreads; } - set { MaxThreads = value; } - } - - /// - /// Get the number of work items in the queue. - /// - public override int WaitingCallbacks - { - get - { - ValidateNotDisposed(); - return _workItemsQueue.Count; - } - } + { + get { return MaxThreads; } + set { MaxThreads = value; } + } + + /// + /// Get the number of work items in the queue. + /// + public override int WaitingCallbacks + { + get + { + ValidateNotDisposed(); + return _workItemsQueue.Count; + } + } /// /// Get an array with all the state objects of the currently running items. @@ -1538,7 +1542,7 @@ namespace Amib.Threading get { return _stpStartInfo.AsReadOnly(); } } - /// + /// /// Start the thread pool if it was started suspended. /// If it is already running, this method is ignored. /// @@ -1589,7 +1593,7 @@ namespace Amib.Threading } } - /// + /// /// Wait for the thread pool to be idle /// public override bool WaitForIdle(int millisecondsTimeout) @@ -1618,9 +1622,9 @@ namespace Amib.Threading } } - internal override void PreQueueWorkItem() + internal override void PreQueueWorkItem() { - ValidateNotDisposed(); + ValidateNotDisposed(); } #endregion @@ -1672,7 +1676,7 @@ namespace Amib.Threading ManualResetEvent anActionCompleted = new ManualResetEvent(false); ChoiceIndex choiceIndex = new ChoiceIndex(); - + int i = 0; foreach (Action action in actions) { @@ -1681,8 +1685,9 @@ namespace Amib.Threading workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); }); ++i; } - workItemsGroup.Start(); + workItemsGroup.Start(); anActionCompleted.WaitOne(); + anActionCompleted.Dispose(); return choiceIndex._index; } @@ -1693,7 +1698,7 @@ namespace Amib.Threading /// /// Actions to execute public int Choice(params Action[] actions) - { + { return Choice((IEnumerable)actions); } @@ -1727,6 +1732,6 @@ namespace Amib.Threading Pipe(pipeState, (IEnumerable>)actions); } #endregion - } - #endregion + } + #endregion } -- cgit v1.1