From 854dcd1abddc3eef33da953592deb61133e5e7ed Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 1 May 2013 23:00:46 +0100 Subject: Fix SmartThreadPool line endings in recent update from dos to unix --- ThirdParty/SmartThreadPool/CallerThreadContext.cs | 276 +- .../SmartThreadPool/CanceledWorkItemsGroup.cs | 26 +- ThirdParty/SmartThreadPool/EventWaitHandle.cs | 206 +- .../SmartThreadPool/EventWaitHandleFactory.cs | 164 +- ThirdParty/SmartThreadPool/Exceptions.cs | 222 +- ThirdParty/SmartThreadPool/Interfaces.cs | 1256 +++---- ThirdParty/SmartThreadPool/InternalInterfaces.cs | 54 +- ThirdParty/SmartThreadPool/PriorityQueue.cs | 478 +-- .../SmartThreadPool/Properties/AssemblyInfo.cs | 46 +- ThirdParty/SmartThreadPool/SLExt.cs | 32 +- ThirdParty/SmartThreadPool/STPEventWaitHandle.cs | 122 +- .../SmartThreadPool/STPPerformanceCounter.cs | 896 ++--- ThirdParty/SmartThreadPool/STPStartInfo.cs | 424 +-- .../SmartThreadPool/SmartThreadPool.ThreadEntry.cs | 118 +- ThirdParty/SmartThreadPool/SmartThreadPool.cs | 3464 ++++++++++---------- .../SmartThreadPool/SynchronizedDictionary.cs | 178 +- ThirdParty/SmartThreadPool/WIGStartInfo.cs | 342 +- .../SmartThreadPool/WorkItem.WorkItemResult.cs | 380 +-- ThirdParty/SmartThreadPool/WorkItemFactory.cs | 686 ++-- ThirdParty/SmartThreadPool/WorkItemInfo.cs | 138 +- .../SmartThreadPool/WorkItemResultTWrapper.cs | 256 +- ThirdParty/SmartThreadPool/WorkItemsGroup.cs | 722 ++-- ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs | 940 +++--- ThirdParty/SmartThreadPool/WorkItemsQueue.cs | 1290 ++++---- 24 files changed, 6358 insertions(+), 6358 deletions(-) diff --git a/ThirdParty/SmartThreadPool/CallerThreadContext.cs b/ThirdParty/SmartThreadPool/CallerThreadContext.cs index 2177241..e63add5 100644 --- a/ThirdParty/SmartThreadPool/CallerThreadContext.cs +++ b/ThirdParty/SmartThreadPool/CallerThreadContext.cs @@ -1,138 +1,138 @@ - -#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - -using System; -using System.Diagnostics; -using System.Threading; -using System.Reflection; -using System.Web; -using System.Runtime.Remoting.Messaging; - - -namespace Amib.Threading.Internal -{ -#region CallerThreadContext class - - /// - /// This class stores the caller call context in order to restore - /// it when the work item is executed in the thread pool environment. - /// - internal class CallerThreadContext - { -#region Prepare reflection information - - // Cached type information. - private static readonly MethodInfo getLogicalCallContextMethodInfo = - typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); - - private static readonly MethodInfo setLogicalCallContextMethodInfo = - typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); - - private static string HttpContextSlotName = GetHttpContextSlotName(); - - private static string GetHttpContextSlotName() - { - FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic); - - if (fi != null) - { - return (string) fi.GetValue(null); - } - - return "HttpContext"; - } - - #endregion - -#region Private fields - - private HttpContext _httpContext; - private LogicalCallContext _callContext; - - #endregion - - /// - /// Constructor - /// - private CallerThreadContext() - { - } - - public bool CapturedCallContext - { - get - { - return (null != _callContext); - } - } - - public bool CapturedHttpContext - { - get - { - return (null != _httpContext); - } - } - - /// - /// Captures the current thread context - /// - /// - public static CallerThreadContext Capture( - bool captureCallContext, - bool captureHttpContext) - { - Debug.Assert(captureCallContext || captureHttpContext); - - CallerThreadContext callerThreadContext = new CallerThreadContext(); - - // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture() - // Capture Call Context - if(captureCallContext && (getLogicalCallContextMethodInfo != null)) - { - callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null); - if (callerThreadContext._callContext != null) - { - callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone(); - } - } - - // Capture httpContext - if (captureHttpContext && (null != HttpContext.Current)) - { - callerThreadContext._httpContext = HttpContext.Current; - } - - return callerThreadContext; - } - - /// - /// Applies the thread context stored earlier - /// - /// - public static void Apply(CallerThreadContext callerThreadContext) - { - if (null == callerThreadContext) - { - throw new ArgumentNullException("callerThreadContext"); - } - - // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run() - // Restore call context - if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null)) - { - setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext }); - } - - // Restore HttpContext - if (callerThreadContext._httpContext != null) - { - HttpContext.Current = callerThreadContext._httpContext; - //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext); - } - } - } - - #endregion -} -#endif + +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + +using System; +using System.Diagnostics; +using System.Threading; +using System.Reflection; +using System.Web; +using System.Runtime.Remoting.Messaging; + + +namespace Amib.Threading.Internal +{ +#region CallerThreadContext class + + /// + /// This class stores the caller call context in order to restore + /// it when the work item is executed in the thread pool environment. + /// + internal class CallerThreadContext + { +#region Prepare reflection information + + // Cached type information. + private static readonly MethodInfo getLogicalCallContextMethodInfo = + typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); + + private static readonly MethodInfo setLogicalCallContextMethodInfo = + typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); + + private static string HttpContextSlotName = GetHttpContextSlotName(); + + private static string GetHttpContextSlotName() + { + FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic); + + if (fi != null) + { + return (string) fi.GetValue(null); + } + + return "HttpContext"; + } + + #endregion + +#region Private fields + + private HttpContext _httpContext; + private LogicalCallContext _callContext; + + #endregion + + /// + /// Constructor + /// + private CallerThreadContext() + { + } + + public bool CapturedCallContext + { + get + { + return (null != _callContext); + } + } + + public bool CapturedHttpContext + { + get + { + return (null != _httpContext); + } + } + + /// + /// Captures the current thread context + /// + /// + public static CallerThreadContext Capture( + bool captureCallContext, + bool captureHttpContext) + { + Debug.Assert(captureCallContext || captureHttpContext); + + CallerThreadContext callerThreadContext = new CallerThreadContext(); + + // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture() + // Capture Call Context + if(captureCallContext && (getLogicalCallContextMethodInfo != null)) + { + callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null); + if (callerThreadContext._callContext != null) + { + callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone(); + } + } + + // Capture httpContext + if (captureHttpContext && (null != HttpContext.Current)) + { + callerThreadContext._httpContext = HttpContext.Current; + } + + return callerThreadContext; + } + + /// + /// Applies the thread context stored earlier + /// + /// + public static void Apply(CallerThreadContext callerThreadContext) + { + if (null == callerThreadContext) + { + throw new ArgumentNullException("callerThreadContext"); + } + + // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run() + // Restore call context + if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null)) + { + setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext }); + } + + // Restore HttpContext + if (callerThreadContext._httpContext != null) + { + HttpContext.Current = callerThreadContext._httpContext; + //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext); + } + } + } + + #endregion +} +#endif diff --git a/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs index 4a2a3e7..5752957 100644 --- a/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs +++ b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs @@ -1,14 +1,14 @@ -namespace Amib.Threading.Internal -{ - internal class CanceledWorkItemsGroup - { - public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup(); - - public CanceledWorkItemsGroup() - { - IsCanceled = false; - } - - public bool IsCanceled { get; set; } - } +namespace Amib.Threading.Internal +{ + internal class CanceledWorkItemsGroup + { + public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup(); + + public CanceledWorkItemsGroup() + { + IsCanceled = false; + } + + public bool IsCanceled { get; set; } + } } \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/EventWaitHandle.cs b/ThirdParty/SmartThreadPool/EventWaitHandle.cs index 70a1a29..25be07a 100644 --- a/ThirdParty/SmartThreadPool/EventWaitHandle.cs +++ b/ThirdParty/SmartThreadPool/EventWaitHandle.cs @@ -1,104 +1,104 @@ -#if (_WINDOWS_CE) - -using System; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Amib.Threading.Internal -{ - /// - /// EventWaitHandle class - /// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation. - /// So I wrote this class to implement these two methods with some of their overloads. - /// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny. - /// Note that this class doesn't even inherit from WaitHandle! - /// - public class STPEventWaitHandle - { - #region Public Constants - - public const int WaitTimeout = Timeout.Infinite; - - #endregion - - #region Private External Constants - - private const Int32 WAIT_FAILED = -1; - private const Int32 WAIT_TIMEOUT = 0x102; - private const UInt32 INFINITE = 0xFFFFFFFF; - - #endregion - - #region WaitAll and WaitAny - - internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) - { - return waitHandle.WaitOne(millisecondsTimeout, exitContext); - } - - private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles) - { - IntPtr[] nativeHandles = new IntPtr[waitHandles.Length]; - for (int i = 0; i < waitHandles.Length; i++) - { - nativeHandles[i] = waitHandles[i].Handle; - } - return nativeHandles; - } - - public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; - - IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); - - int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout); - - if (result == WAIT_TIMEOUT || result == WAIT_FAILED) - { - return false; - } - - return true; - } - - - public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; - - IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); - - int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout); - - if (result >= 0 && result < waitHandles.Length) - { - return result; - } - - return -1; - } - - public static int WaitAny(WaitHandle[] waitHandles) - { - return WaitAny(waitHandles, Timeout.Infinite, false); - } - - public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext) - { - int millisecondsTimeout = (int)timeout.TotalMilliseconds; - - return WaitAny(waitHandles, millisecondsTimeout, false); - } - - #endregion - - #region External methods - - [DllImport("coredll.dll", SetLastError = true)] - public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds); - - #endregion - } -} +#if (_WINDOWS_CE) + +using System; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Amib.Threading.Internal +{ + /// + /// EventWaitHandle class + /// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation. + /// So I wrote this class to implement these two methods with some of their overloads. + /// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny. + /// Note that this class doesn't even inherit from WaitHandle! + /// + public class STPEventWaitHandle + { + #region Public Constants + + public const int WaitTimeout = Timeout.Infinite; + + #endregion + + #region Private External Constants + + private const Int32 WAIT_FAILED = -1; + private const Int32 WAIT_TIMEOUT = 0x102; + private const UInt32 INFINITE = 0xFFFFFFFF; + + #endregion + + #region WaitAll and WaitAny + + internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) + { + return waitHandle.WaitOne(millisecondsTimeout, exitContext); + } + + private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles) + { + IntPtr[] nativeHandles = new IntPtr[waitHandles.Length]; + for (int i = 0; i < waitHandles.Length; i++) + { + nativeHandles[i] = waitHandles[i].Handle; + } + return nativeHandles; + } + + public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; + + IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); + + int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout); + + if (result == WAIT_TIMEOUT || result == WAIT_FAILED) + { + return false; + } + + return true; + } + + + public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; + + IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); + + int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout); + + if (result >= 0 && result < waitHandles.Length) + { + return result; + } + + return -1; + } + + public static int WaitAny(WaitHandle[] waitHandles) + { + return WaitAny(waitHandles, Timeout.Infinite, false); + } + + public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext) + { + int millisecondsTimeout = (int)timeout.TotalMilliseconds; + + return WaitAny(waitHandles, millisecondsTimeout, false); + } + + #endregion + + #region External methods + + [DllImport("coredll.dll", SetLastError = true)] + public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds); + + #endregion + } +} #endif \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs index 2f8c55b..3c9c849 100644 --- a/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs +++ b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs @@ -1,82 +1,82 @@ -using System.Threading; - -#if (_WINDOWS_CE) -using System; -using System.Runtime.InteropServices; -#endif - -namespace Amib.Threading.Internal -{ - /// - /// EventWaitHandleFactory class. - /// This is a static class that creates AutoResetEvent and ManualResetEvent objects. - /// In WindowCE the WaitForMultipleObjects API fails to use the Handle property - /// of XxxResetEvent. It can use only handles that were created by the CreateEvent API. - /// Consequently this class creates the needed XxxResetEvent and replaces the handle if - /// it's a WindowsCE OS. - /// - public static class EventWaitHandleFactory - { - /// - /// Create a new AutoResetEvent object - /// - /// Return a new AutoResetEvent object - public static AutoResetEvent CreateAutoResetEvent() - { - AutoResetEvent waitHandle = new AutoResetEvent(false); - -#if (_WINDOWS_CE) - ReplaceEventHandle(waitHandle, false, false); -#endif - - return waitHandle; - } - - /// - /// Create a new ManualResetEvent object - /// - /// Return a new ManualResetEvent object - public static ManualResetEvent CreateManualResetEvent(bool initialState) - { - ManualResetEvent waitHandle = new ManualResetEvent(initialState); - -#if (_WINDOWS_CE) - ReplaceEventHandle(waitHandle, true, initialState); -#endif - - return waitHandle; - } - -#if (_WINDOWS_CE) - - /// - /// Replace the event handle - /// - /// The WaitHandle object which its handle needs to be replaced. - /// Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false) - /// The initial state of the event - private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState) - { - // Store the old handle - IntPtr oldHandle = waitHandle.Handle; - - // Create a new event - IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null); - - // Replace the old event with the new event - waitHandle.Handle = newHandle; - - // Close the old event - CloseHandle (oldHandle); - } - - [DllImport("coredll.dll", SetLastError = true)] - public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); - - //Handle - [DllImport("coredll.dll", SetLastError = true)] - public static extern bool CloseHandle(IntPtr hObject); -#endif - - } -} +using System.Threading; + +#if (_WINDOWS_CE) +using System; +using System.Runtime.InteropServices; +#endif + +namespace Amib.Threading.Internal +{ + /// + /// EventWaitHandleFactory class. + /// This is a static class that creates AutoResetEvent and ManualResetEvent objects. + /// In WindowCE the WaitForMultipleObjects API fails to use the Handle property + /// of XxxResetEvent. It can use only handles that were created by the CreateEvent API. + /// Consequently this class creates the needed XxxResetEvent and replaces the handle if + /// it's a WindowsCE OS. + /// + public static class EventWaitHandleFactory + { + /// + /// Create a new AutoResetEvent object + /// + /// Return a new AutoResetEvent object + public static AutoResetEvent CreateAutoResetEvent() + { + AutoResetEvent waitHandle = new AutoResetEvent(false); + +#if (_WINDOWS_CE) + ReplaceEventHandle(waitHandle, false, false); +#endif + + return waitHandle; + } + + /// + /// Create a new ManualResetEvent object + /// + /// Return a new ManualResetEvent object + public static ManualResetEvent CreateManualResetEvent(bool initialState) + { + ManualResetEvent waitHandle = new ManualResetEvent(initialState); + +#if (_WINDOWS_CE) + ReplaceEventHandle(waitHandle, true, initialState); +#endif + + return waitHandle; + } + +#if (_WINDOWS_CE) + + /// + /// Replace the event handle + /// + /// The WaitHandle object which its handle needs to be replaced. + /// Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false) + /// The initial state of the event + private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState) + { + // Store the old handle + IntPtr oldHandle = waitHandle.Handle; + + // Create a new event + IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null); + + // Replace the old event with the new event + waitHandle.Handle = newHandle; + + // Close the old event + CloseHandle (oldHandle); + } + + [DllImport("coredll.dll", SetLastError = true)] + public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); + + //Handle + [DllImport("coredll.dll", SetLastError = true)] + public static extern bool CloseHandle(IntPtr hObject); +#endif + + } +} diff --git a/ThirdParty/SmartThreadPool/Exceptions.cs b/ThirdParty/SmartThreadPool/Exceptions.cs index 8e66ce9..6c6a88b 100644 --- a/ThirdParty/SmartThreadPool/Exceptions.cs +++ b/ThirdParty/SmartThreadPool/Exceptions.cs @@ -1,111 +1,111 @@ -using System; -#if !(_WINDOWS_CE) -using System.Runtime.Serialization; -#endif - -namespace Amib.Threading -{ - #region Exceptions - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been canceled - /// - public sealed partial class WorkItemCancelException : Exception - { - public WorkItemCancelException() - { - } - - public WorkItemCancelException(string message) - : base(message) - { - } - - public WorkItemCancelException(string message, Exception e) - : base(message, e) - { - } - } - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been timed out - /// - public sealed partial class WorkItemTimeoutException : Exception - { - public WorkItemTimeoutException() - { - } - - public WorkItemTimeoutException(string message) - : base(message) - { - } - - public WorkItemTimeoutException(string message, Exception e) - : base(message, e) - { - } - } - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been timed out - /// - public sealed partial class WorkItemResultException : Exception - { - public WorkItemResultException() - { - } - - public WorkItemResultException(string message) - : base(message) - { - } - - public WorkItemResultException(string message, Exception e) - : base(message, e) - { - } - } - - -#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - /// - /// Represents an exception in case IWorkItemResult.GetResult has been canceled - /// - [Serializable] - public sealed partial class WorkItemCancelException - { - public WorkItemCancelException(SerializationInfo si, StreamingContext sc) - : base(si, sc) - { - } - } - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been timed out - /// - [Serializable] - public sealed partial class WorkItemTimeoutException - { - public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) - : base(si, sc) - { - } - } - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been timed out - /// - [Serializable] - public sealed partial class WorkItemResultException - { - public WorkItemResultException(SerializationInfo si, StreamingContext sc) - : base(si, sc) - { - } - } - -#endif - - #endregion -} +using System; +#if !(_WINDOWS_CE) +using System.Runtime.Serialization; +#endif + +namespace Amib.Threading +{ + #region Exceptions + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been canceled + /// + public sealed partial class WorkItemCancelException : Exception + { + public WorkItemCancelException() + { + } + + public WorkItemCancelException(string message) + : base(message) + { + } + + public WorkItemCancelException(string message, Exception e) + : base(message, e) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + public sealed partial class WorkItemTimeoutException : Exception + { + public WorkItemTimeoutException() + { + } + + public WorkItemTimeoutException(string message) + : base(message) + { + } + + public WorkItemTimeoutException(string message, Exception e) + : base(message, e) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + public sealed partial class WorkItemResultException : Exception + { + public WorkItemResultException() + { + } + + public WorkItemResultException(string message) + : base(message) + { + } + + public WorkItemResultException(string message, Exception e) + : base(message, e) + { + } + } + + +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + /// + /// Represents an exception in case IWorkItemResult.GetResult has been canceled + /// + [Serializable] + public sealed partial class WorkItemCancelException + { + public WorkItemCancelException(SerializationInfo si, StreamingContext sc) + : base(si, sc) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + [Serializable] + public sealed partial class WorkItemTimeoutException + { + public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) + : base(si, sc) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + [Serializable] + public sealed partial class WorkItemResultException + { + public WorkItemResultException(SerializationInfo si, StreamingContext sc) + : base(si, sc) + { + } + } + +#endif + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/Interfaces.cs b/ThirdParty/SmartThreadPool/Interfaces.cs index 29c8a3e..513422f 100644 --- a/ThirdParty/SmartThreadPool/Interfaces.cs +++ b/ThirdParty/SmartThreadPool/Interfaces.cs @@ -1,628 +1,628 @@ -using System; -using System.Threading; - -namespace Amib.Threading -{ - #region Delegates - - /// - /// A delegate that represents the method to run as the work item - /// - /// A state object for the method to run - public delegate object WorkItemCallback(object state); - - /// - /// A delegate to call after the WorkItemCallback completed - /// - /// The work item result object - public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); - - /// - /// A delegate to call after the WorkItemCallback completed - /// - /// The work item result object - public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); - - /// - /// A delegate to call when a WorkItemsGroup becomes idle - /// - /// A reference to the WorkItemsGroup that became idle - public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup); - - /// - /// A delegate to call after a thread is created, but before - /// it's first use. - /// - public delegate void ThreadInitializationHandler(); - - /// - /// A delegate to call when a thread is about to exit, after - /// it is no longer belong to the pool. - /// - public delegate void ThreadTerminationHandler(); - - #endregion - - #region WorkItem Priority - - /// - /// Defines the availeable priorities of a work item. - /// The higher the priority a work item has, the sooner - /// it will be executed. - /// - public enum WorkItemPriority - { - Lowest, - BelowNormal, - Normal, - AboveNormal, - Highest, - } - - #endregion - - #region IWorkItemsGroup interface - - /// - /// IWorkItemsGroup interface - /// Created by SmartThreadPool.CreateWorkItemsGroup() - /// - public interface IWorkItemsGroup - { - /// - /// Get/Set the name of the WorkItemsGroup - /// - string Name { get; set; } - - /// - /// Get/Set the maximum number of workitem that execute cocurrency on the thread pool - /// - int Concurrency { get; set; } - - /// - /// Get the number of work items waiting in the queue. - /// - int WaitingCallbacks { get; } - - /// - /// Get an array with all the state objects of the currently running items. - /// The array represents a snap shot and impact performance. - /// - object[] GetStates(); - - /// - /// Get the WorkItemsGroup start information - /// - WIGStartInfo WIGStartInfo { get; } - - /// - /// Starts to execute work items - /// - void Start(); - - /// - /// Cancel all the work items. - /// Same as Cancel(false) - /// - void Cancel(); - - /// - /// Cancel all work items using thread abortion - /// - /// True to stop work items by raising ThreadAbortException - void Cancel(bool abortExecution); - - /// - /// Wait for all work item to complete. - /// - void WaitForIdle(); - - /// - /// Wait for all work item to complete, until timeout expired - /// - /// How long to wait for the work items to complete - /// Returns true if work items completed within the timeout, otherwise false. - bool WaitForIdle(TimeSpan timeout); - - /// - /// Wait for all work item to complete, until timeout expired - /// - /// How long to wait for the work items to complete in milliseconds - /// Returns true if work items completed within the timeout, otherwise false. - bool WaitForIdle(int millisecondsTimeout); - - /// - /// IsIdle is true when there are no work items running or queued. - /// - bool IsIdle { get; } - - /// - /// This event is fired when all work items are completed. - /// (When IsIdle changes to true) - /// This event only work on WorkItemsGroup. On SmartThreadPool - /// it throws the NotImplementedException. - /// - event WorkItemsGroupIdleHandler OnIdle; - - #region QueueWorkItem - - /// - /// Queue a work item - /// - /// A callback to execute - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback); - - /// - /// Queue a work item - /// - /// A callback to execute - /// The priority of the work item - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// The work item priority - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// The work item priority - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// The work item priority - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); - - /// - /// Queue a work item - /// - /// Work item info - /// A callback to execute - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); - - /// - /// Queue a work item - /// - /// Work item information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); - - #endregion - - #region QueueWorkItem(Action<...>) - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem(Action action); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, T arg); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority); - - #endregion - - #region QueueWorkItem(Func<...>) - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult<TResult> object. - /// its GetResult() returns a TResult object - IWorkItemResult QueueWorkItem(Func func); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult<TResult> object. - /// its GetResult() returns a TResult object - IWorkItemResult QueueWorkItem(Func func, T arg); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult<TResult> object. - /// its GetResult() returns a TResult object - IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult<TResult> object. - /// its GetResult() returns a TResult object - IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult<TResult> object. - /// its GetResult() returns a TResult object - IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4); - - #endregion - } - - #endregion - - #region CallToPostExecute enumerator - - [Flags] - public enum CallToPostExecute - { - /// - /// Never call to the PostExecute call back - /// - Never = 0x00, - - /// - /// Call to the PostExecute only when the work item is cancelled - /// - WhenWorkItemCanceled = 0x01, - - /// - /// Call to the PostExecute only when the work item is not cancelled - /// - WhenWorkItemNotCanceled = 0x02, - - /// - /// Always call to the PostExecute - /// - Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled, - } - - #endregion - - #region IWorkItemResult interface - - /// - /// The common interface of IWorkItemResult and IWorkItemResult<T> - /// - public interface IWaitableResult - { - /// - /// This method intent is for internal use. - /// - /// - IWorkItemResult GetWorkItemResult(); - - /// - /// This method intent is for internal use. - /// - /// - IWorkItemResult GetWorkItemResultT(); - } - - /// - /// IWorkItemResult interface. - /// Created when a WorkItemCallback work item is queued. - /// - public interface IWorkItemResult : IWorkItemResult - { - } - - /// - /// IWorkItemResult<TResult> interface. - /// Created when a Func<TResult> work item is queued. - /// - public interface IWorkItemResult : IWaitableResult - { - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits. - /// - /// The result of the work item - TResult GetResult(); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - TResult GetResult( - int millisecondsTimeout, - bool exitContext); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - TResult GetResult( - TimeSpan timeout, - bool exitContext); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// Timeout in milliseconds, or -1 for infinite - /// - /// 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 blocking if needed - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - TResult GetResult( - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - TResult GetResult( - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits. - /// - /// Filled with the exception if one was thrown - /// The result of the work item - TResult GetResult(out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// - /// - /// Filled with the exception if one was thrown - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - TResult GetResult( - int millisecondsTimeout, - bool exitContext, - out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// - /// Filled with the exception if one was thrown - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - TResult GetResult( - TimeSpan timeout, - bool exitContext, - out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// Timeout in milliseconds, or -1 for infinite - /// - /// 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 blocking if needed - /// Filled with the exception if one was thrown - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - TResult GetResult( - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle, - out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// The result of the work item - /// - /// Filled with the exception if one was thrown - /// - /// - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - TResult GetResult( - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle, - out Exception e); - - /// - /// Gets an indication whether the asynchronous operation has completed. - /// - bool IsCompleted { get; } - - /// - /// Gets an indication whether the asynchronous operation has been canceled. - /// - bool IsCanceled { get; } - - /// - /// Gets the user-defined object that contains context data - /// for the work item method. - /// - object State { get; } - - /// - /// Same as Cancel(false). - /// - bool Cancel(); - - /// - /// Cancel the work item execution. - /// If the work item is in the queue then it won't execute - /// If the work item is completed, it will remain completed - /// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled - /// property to check if the work item has been cancelled. If the abortExecution is set to true then - /// the Smart Thread Pool will send an AbortException to the running thread to stop the execution - /// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException. - /// If the work item is already cancelled it will remain cancelled - /// - /// When true send an AbortException to the executing thread. - /// Returns true if the work item was not completed, otherwise false. - bool Cancel(bool abortExecution); - - /// - /// Get the work item's priority - /// - WorkItemPriority WorkItemPriority { get; } - - /// - /// Return the result, same as GetResult() - /// - TResult Result { get; } - - /// - /// Returns the exception if occured otherwise returns null. - /// - object Exception { get; } - } - - #endregion - - #region .NET 3.5 - - // All these delegate are built-in .NET 3.5 - // Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity. - - public delegate void Action(); - public delegate void Action(T1 arg1, T2 arg2); - public delegate void Action(T1 arg1, T2 arg2, T3 arg3); - public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4); - - public delegate TResult Func(); - public delegate TResult Func(T arg1); - public delegate TResult Func(T1 arg1, T2 arg2); - public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); - public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); - - #endregion -} +using System; +using System.Threading; + +namespace Amib.Threading +{ + #region Delegates + + /// + /// A delegate that represents the method to run as the work item + /// + /// A state object for the method to run + public delegate object WorkItemCallback(object state); + + /// + /// A delegate to call after the WorkItemCallback completed + /// + /// The work item result object + public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); + + /// + /// A delegate to call after the WorkItemCallback completed + /// + /// The work item result object + public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); + + /// + /// A delegate to call when a WorkItemsGroup becomes idle + /// + /// A reference to the WorkItemsGroup that became idle + public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup); + + /// + /// A delegate to call after a thread is created, but before + /// it's first use. + /// + public delegate void ThreadInitializationHandler(); + + /// + /// A delegate to call when a thread is about to exit, after + /// it is no longer belong to the pool. + /// + public delegate void ThreadTerminationHandler(); + + #endregion + + #region WorkItem Priority + + /// + /// Defines the availeable priorities of a work item. + /// The higher the priority a work item has, the sooner + /// it will be executed. + /// + public enum WorkItemPriority + { + Lowest, + BelowNormal, + Normal, + AboveNormal, + Highest, + } + + #endregion + + #region IWorkItemsGroup interface + + /// + /// IWorkItemsGroup interface + /// Created by SmartThreadPool.CreateWorkItemsGroup() + /// + public interface IWorkItemsGroup + { + /// + /// Get/Set the name of the WorkItemsGroup + /// + string Name { get; set; } + + /// + /// Get/Set the maximum number of workitem that execute cocurrency on the thread pool + /// + int Concurrency { get; set; } + + /// + /// Get the number of work items waiting in the queue. + /// + int WaitingCallbacks { get; } + + /// + /// Get an array with all the state objects of the currently running items. + /// The array represents a snap shot and impact performance. + /// + object[] GetStates(); + + /// + /// Get the WorkItemsGroup start information + /// + WIGStartInfo WIGStartInfo { get; } + + /// + /// Starts to execute work items + /// + void Start(); + + /// + /// Cancel all the work items. + /// Same as Cancel(false) + /// + void Cancel(); + + /// + /// Cancel all work items using thread abortion + /// + /// True to stop work items by raising ThreadAbortException + void Cancel(bool abortExecution); + + /// + /// Wait for all work item to complete. + /// + void WaitForIdle(); + + /// + /// Wait for all work item to complete, until timeout expired + /// + /// How long to wait for the work items to complete + /// Returns true if work items completed within the timeout, otherwise false. + bool WaitForIdle(TimeSpan timeout); + + /// + /// Wait for all work item to complete, until timeout expired + /// + /// How long to wait for the work items to complete in milliseconds + /// Returns true if work items completed within the timeout, otherwise false. + bool WaitForIdle(int millisecondsTimeout); + + /// + /// IsIdle is true when there are no work items running or queued. + /// + bool IsIdle { get; } + + /// + /// This event is fired when all work items are completed. + /// (When IsIdle changes to true) + /// This event only work on WorkItemsGroup. On SmartThreadPool + /// it throws the NotImplementedException. + /// + event WorkItemsGroupIdleHandler OnIdle; + + #region QueueWorkItem + + /// + /// Queue a work item + /// + /// A callback to execute + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback); + + /// + /// Queue a work item + /// + /// A callback to execute + /// The priority of the work item + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// The work item priority + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// The work item priority + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// The work item priority + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// Work item info + /// A callback to execute + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); + + /// + /// Queue a work item + /// + /// Work item information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); + + #endregion + + #region QueueWorkItem(Action<...>) + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T arg); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority); + + #endregion + + #region QueueWorkItem(Func<...>) + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T arg); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + #endregion + } + + #endregion + + #region CallToPostExecute enumerator + + [Flags] + public enum CallToPostExecute + { + /// + /// Never call to the PostExecute call back + /// + Never = 0x00, + + /// + /// Call to the PostExecute only when the work item is cancelled + /// + WhenWorkItemCanceled = 0x01, + + /// + /// Call to the PostExecute only when the work item is not cancelled + /// + WhenWorkItemNotCanceled = 0x02, + + /// + /// Always call to the PostExecute + /// + Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled, + } + + #endregion + + #region IWorkItemResult interface + + /// + /// The common interface of IWorkItemResult and IWorkItemResult<T> + /// + public interface IWaitableResult + { + /// + /// This method intent is for internal use. + /// + /// + IWorkItemResult GetWorkItemResult(); + + /// + /// This method intent is for internal use. + /// + /// + IWorkItemResult GetWorkItemResultT(); + } + + /// + /// IWorkItemResult interface. + /// Created when a WorkItemCallback work item is queued. + /// + public interface IWorkItemResult : IWorkItemResult + { + } + + /// + /// IWorkItemResult<TResult> interface. + /// Created when a Func<TResult> work item is queued. + /// + public interface IWorkItemResult : IWaitableResult + { + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits. + /// + /// The result of the work item + TResult GetResult(); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + int millisecondsTimeout, + bool exitContext); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + TimeSpan timeout, + bool exitContext); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// Timeout in milliseconds, or -1 for infinite + /// + /// 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 blocking if needed + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits. + /// + /// Filled with the exception if one was thrown + /// The result of the work item + TResult GetResult(out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// + /// + /// Filled with the exception if one was thrown + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + int millisecondsTimeout, + bool exitContext, + out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// + /// Filled with the exception if one was thrown + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + TimeSpan timeout, + bool exitContext, + out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// Timeout in milliseconds, or -1 for infinite + /// + /// 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 blocking if needed + /// Filled with the exception if one was thrown + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle, + out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// The result of the work item + /// + /// Filled with the exception if one was thrown + /// + /// + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle, + out Exception e); + + /// + /// Gets an indication whether the asynchronous operation has completed. + /// + bool IsCompleted { get; } + + /// + /// Gets an indication whether the asynchronous operation has been canceled. + /// + bool IsCanceled { get; } + + /// + /// Gets the user-defined object that contains context data + /// for the work item method. + /// + object State { get; } + + /// + /// Same as Cancel(false). + /// + bool Cancel(); + + /// + /// Cancel the work item execution. + /// If the work item is in the queue then it won't execute + /// If the work item is completed, it will remain completed + /// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled + /// property to check if the work item has been cancelled. If the abortExecution is set to true then + /// the Smart Thread Pool will send an AbortException to the running thread to stop the execution + /// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException. + /// If the work item is already cancelled it will remain cancelled + /// + /// When true send an AbortException to the executing thread. + /// Returns true if the work item was not completed, otherwise false. + bool Cancel(bool abortExecution); + + /// + /// Get the work item's priority + /// + WorkItemPriority WorkItemPriority { get; } + + /// + /// Return the result, same as GetResult() + /// + TResult Result { get; } + + /// + /// Returns the exception if occured otherwise returns null. + /// + object Exception { get; } + } + + #endregion + + #region .NET 3.5 + + // All these delegate are built-in .NET 3.5 + // Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity. + + public delegate void Action(); + public delegate void Action(T1 arg1, T2 arg2); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + public delegate TResult Func(); + public delegate TResult Func(T arg1); + public delegate TResult Func(T1 arg1, T2 arg2); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/InternalInterfaces.cs b/ThirdParty/SmartThreadPool/InternalInterfaces.cs index 8be7161..0072e10 100644 --- a/ThirdParty/SmartThreadPool/InternalInterfaces.cs +++ b/ThirdParty/SmartThreadPool/InternalInterfaces.cs @@ -1,27 +1,27 @@ - -namespace Amib.Threading.Internal -{ - /// - /// An internal delegate to call when the WorkItem starts or completes - /// - internal delegate void WorkItemStateCallback(WorkItem workItem); - - internal interface IInternalWorkItemResult - { - event WorkItemStateCallback OnWorkItemStarted; - event WorkItemStateCallback OnWorkItemCompleted; - } - - internal interface IInternalWaitableResult - { - /// - /// This method is intent for internal use. - /// - IWorkItemResult GetWorkItemResult(); - } - - public interface IHasWorkItemPriority - { - WorkItemPriority WorkItemPriority { get; } - } -} + +namespace Amib.Threading.Internal +{ + /// + /// An internal delegate to call when the WorkItem starts or completes + /// + internal delegate void WorkItemStateCallback(WorkItem workItem); + + internal interface IInternalWorkItemResult + { + event WorkItemStateCallback OnWorkItemStarted; + event WorkItemStateCallback OnWorkItemCompleted; + } + + internal interface IInternalWaitableResult + { + /// + /// This method is intent for internal use. + /// + IWorkItemResult GetWorkItemResult(); + } + + public interface IHasWorkItemPriority + { + WorkItemPriority WorkItemPriority { get; } + } +} diff --git a/ThirdParty/SmartThreadPool/PriorityQueue.cs b/ThirdParty/SmartThreadPool/PriorityQueue.cs index 6245fd8..409c879 100644 --- a/ThirdParty/SmartThreadPool/PriorityQueue.cs +++ b/ThirdParty/SmartThreadPool/PriorityQueue.cs @@ -1,239 +1,239 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; - -namespace Amib.Threading.Internal -{ - #region PriorityQueue class - - /// - /// PriorityQueue class - /// This class is not thread safe because we use external lock - /// - public sealed class PriorityQueue : IEnumerable - { - #region Private members - - /// - /// The number of queues, there is one for each type of priority - /// - private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; - - /// - /// Work items queues. There is one for each type of priority - /// - private readonly LinkedList[] _queues = new LinkedList[_queuesCount]; - - /// - /// The total number of work items within the queues - /// - private int _workItemsCount; - - /// - /// Use with IEnumerable interface - /// - private int _version; - - #endregion - - #region Contructor - - public PriorityQueue() - { - for(int i = 0; i < _queues.Length; ++i) - { - _queues[i] = new LinkedList(); - } - } - - #endregion - - #region Methods - - /// - /// Enqueue a work item. - /// - /// A work item - public void Enqueue(IHasWorkItemPriority workItem) - { - Debug.Assert(null != workItem); - - int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; - Debug.Assert(queueIndex >= 0); - Debug.Assert(queueIndex < _queuesCount); - - _queues[queueIndex].AddLast(workItem); - ++_workItemsCount; - ++_version; - } - - /// - /// Dequeque a work item. - /// - /// Returns the next work item - public IHasWorkItemPriority Dequeue() - { - IHasWorkItemPriority workItem = null; - - if(_workItemsCount > 0) - { - int queueIndex = GetNextNonEmptyQueue(-1); - Debug.Assert(queueIndex >= 0); - workItem = _queues[queueIndex].First.Value; - _queues[queueIndex].RemoveFirst(); - Debug.Assert(null != workItem); - --_workItemsCount; - ++_version; - } - - return workItem; - } - - /// - /// Find the next non empty queue starting at queue queueIndex+1 - /// - /// The index-1 to start from - /// - /// The index of the next non empty queue or -1 if all the queues are empty - /// - private int GetNextNonEmptyQueue(int queueIndex) - { - for(int i = queueIndex+1; i < _queuesCount; ++i) - { - if(_queues[i].Count > 0) - { - return i; - } - } - return -1; - } - - /// - /// The number of work items - /// - public int Count - { - get - { - return _workItemsCount; - } - } - - /// - /// Clear all the work items - /// - public void Clear() - { - if (_workItemsCount > 0) - { - foreach(LinkedList queue in _queues) - { - queue.Clear(); - } - _workItemsCount = 0; - ++_version; - } - } - - #endregion - - #region IEnumerable Members - - /// - /// Returns an enumerator to iterate over the work items - /// - /// Returns an enumerator - public IEnumerator GetEnumerator() - { - return new PriorityQueueEnumerator(this); - } - - #endregion - - #region PriorityQueueEnumerator - - /// - /// The class the implements the enumerator - /// - private class PriorityQueueEnumerator : IEnumerator - { - private readonly PriorityQueue _priorityQueue; - private int _version; - private int _queueIndex; - private IEnumerator _enumerator; - - public PriorityQueueEnumerator(PriorityQueue priorityQueue) - { - _priorityQueue = priorityQueue; - _version = _priorityQueue._version; - _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); - if (_queueIndex >= 0) - { - _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); - } - else - { - _enumerator = null; - } - } - - #region IEnumerator Members - - public void Reset() - { - _version = _priorityQueue._version; - _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); - if (_queueIndex >= 0) - { - _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); - } - else - { - _enumerator = null; - } - } - - public object Current - { - get - { - Debug.Assert(null != _enumerator); - return _enumerator.Current; - } - } - - public bool MoveNext() - { - if (null == _enumerator) - { - return false; - } - - if(_version != _priorityQueue._version) - { - throw new InvalidOperationException("The collection has been modified"); - - } - if (!_enumerator.MoveNext()) - { - _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); - if(-1 == _queueIndex) - { - return false; - } - _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); - _enumerator.MoveNext(); - return true; - } - return true; - } - - #endregion - } - - #endregion - } - - #endregion -} +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Amib.Threading.Internal +{ + #region PriorityQueue class + + /// + /// PriorityQueue class + /// This class is not thread safe because we use external lock + /// + public sealed class PriorityQueue : IEnumerable + { + #region Private members + + /// + /// The number of queues, there is one for each type of priority + /// + private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; + + /// + /// Work items queues. There is one for each type of priority + /// + private readonly LinkedList[] _queues = new LinkedList[_queuesCount]; + + /// + /// The total number of work items within the queues + /// + private int _workItemsCount; + + /// + /// Use with IEnumerable interface + /// + private int _version; + + #endregion + + #region Contructor + + public PriorityQueue() + { + for(int i = 0; i < _queues.Length; ++i) + { + _queues[i] = new LinkedList(); + } + } + + #endregion + + #region Methods + + /// + /// Enqueue a work item. + /// + /// A work item + public void Enqueue(IHasWorkItemPriority workItem) + { + Debug.Assert(null != workItem); + + int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; + Debug.Assert(queueIndex >= 0); + Debug.Assert(queueIndex < _queuesCount); + + _queues[queueIndex].AddLast(workItem); + ++_workItemsCount; + ++_version; + } + + /// + /// Dequeque a work item. + /// + /// Returns the next work item + public IHasWorkItemPriority Dequeue() + { + IHasWorkItemPriority workItem = null; + + if(_workItemsCount > 0) + { + int queueIndex = GetNextNonEmptyQueue(-1); + Debug.Assert(queueIndex >= 0); + workItem = _queues[queueIndex].First.Value; + _queues[queueIndex].RemoveFirst(); + Debug.Assert(null != workItem); + --_workItemsCount; + ++_version; + } + + return workItem; + } + + /// + /// Find the next non empty queue starting at queue queueIndex+1 + /// + /// The index-1 to start from + /// + /// The index of the next non empty queue or -1 if all the queues are empty + /// + private int GetNextNonEmptyQueue(int queueIndex) + { + for(int i = queueIndex+1; i < _queuesCount; ++i) + { + if(_queues[i].Count > 0) + { + return i; + } + } + return -1; + } + + /// + /// The number of work items + /// + public int Count + { + get + { + return _workItemsCount; + } + } + + /// + /// Clear all the work items + /// + public void Clear() + { + if (_workItemsCount > 0) + { + foreach(LinkedList queue in _queues) + { + queue.Clear(); + } + _workItemsCount = 0; + ++_version; + } + } + + #endregion + + #region IEnumerable Members + + /// + /// Returns an enumerator to iterate over the work items + /// + /// Returns an enumerator + public IEnumerator GetEnumerator() + { + return new PriorityQueueEnumerator(this); + } + + #endregion + + #region PriorityQueueEnumerator + + /// + /// The class the implements the enumerator + /// + private class PriorityQueueEnumerator : IEnumerator + { + private readonly PriorityQueue _priorityQueue; + private int _version; + private int _queueIndex; + private IEnumerator _enumerator; + + public PriorityQueueEnumerator(PriorityQueue priorityQueue) + { + _priorityQueue = priorityQueue; + _version = _priorityQueue._version; + _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); + if (_queueIndex >= 0) + { + _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); + } + else + { + _enumerator = null; + } + } + + #region IEnumerator Members + + public void Reset() + { + _version = _priorityQueue._version; + _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); + if (_queueIndex >= 0) + { + _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); + } + else + { + _enumerator = null; + } + } + + public object Current + { + get + { + Debug.Assert(null != _enumerator); + return _enumerator.Current; + } + } + + public bool MoveNext() + { + if (null == _enumerator) + { + return false; + } + + if(_version != _priorityQueue._version) + { + throw new InvalidOperationException("The collection has been modified"); + + } + if (!_enumerator.MoveNext()) + { + _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); + if(-1 == _queueIndex) + { + return false; + } + _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); + _enumerator.MoveNext(); + return true; + } + return true; + } + + #endregion + } + + #endregion + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs index 1651e78..4728c1f 100644 --- a/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs +++ b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs @@ -1,23 +1,23 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Amib.Threading")] -[assembly: AssemblyDescription("Smart Thread Pool")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Amib.Threading")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] -[assembly: Guid("c764a3de-c4f8-434d-85b5-a09830d1e44f")] -[assembly: AssemblyVersion("2.2.3.0")] - -#if (_PUBLISH) -[assembly: InternalsVisibleTo("STPTests,PublicKey=00240000048000009400000006020000002400005253413100040000010001004fe3d39add741ba7c8d52cd1eb0d94c7d79060ad956cbaff0e51c1dce94db10356b261778bc1ac3114b3218434da6fcd8416dd5507653809598f7d2afc422099ce4f6b7b0477f18e6c57c727ef2a7ab6ee56e6b4589fe44cb0e25f2875a3c65ab0383ee33c4dd93023f7ce1218bebc8b7a9a1dac878938f5c4f45ea74b6bd8ad")] -#else -[assembly: InternalsVisibleTo("STPTests")] -#endif - - +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Amib.Threading")] +[assembly: AssemblyDescription("Smart Thread Pool")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Amib.Threading")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: Guid("c764a3de-c4f8-434d-85b5-a09830d1e44f")] +[assembly: AssemblyVersion("2.2.3.0")] + +#if (_PUBLISH) +[assembly: InternalsVisibleTo("STPTests,PublicKey=00240000048000009400000006020000002400005253413100040000010001004fe3d39add741ba7c8d52cd1eb0d94c7d79060ad956cbaff0e51c1dce94db10356b261778bc1ac3114b3218434da6fcd8416dd5507653809598f7d2afc422099ce4f6b7b0477f18e6c57c727ef2a7ab6ee56e6b4589fe44cb0e25f2875a3c65ab0383ee33c4dd93023f7ce1218bebc8b7a9a1dac878938f5c4f45ea74b6bd8ad")] +#else +[assembly: InternalsVisibleTo("STPTests")] +#endif + + diff --git a/ThirdParty/SmartThreadPool/SLExt.cs b/ThirdParty/SmartThreadPool/SLExt.cs index fafff19..23a60bc 100644 --- a/ThirdParty/SmartThreadPool/SLExt.cs +++ b/ThirdParty/SmartThreadPool/SLExt.cs @@ -1,16 +1,16 @@ -#if _SILVERLIGHT - -using System.Threading; - -namespace Amib.Threading -{ - public enum ThreadPriority - { - Lowest, - BelowNormal, - Normal, - AboveNormal, - Highest, - } -} -#endif +#if _SILVERLIGHT + +using System.Threading; + +namespace Amib.Threading +{ + public enum ThreadPriority + { + Lowest, + BelowNormal, + Normal, + AboveNormal, + Highest, + } +} +#endif diff --git a/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs index 3b92645..9b17f69 100644 --- a/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs +++ b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs @@ -1,62 +1,62 @@ -#if !(_WINDOWS_CE) - -using System; -using System.Threading; - -namespace Amib.Threading.Internal -{ -#if _WINDOWS || WINDOWS_PHONE - internal static class STPEventWaitHandle - { - public const int WaitTimeout = Timeout.Infinite; - - internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - return WaitHandle.WaitAll(waitHandles, millisecondsTimeout); - } - - internal static int WaitAny(WaitHandle[] waitHandles) - { - return WaitHandle.WaitAny(waitHandles); - } - - internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - return WaitHandle.WaitAny(waitHandles, millisecondsTimeout); - } - - internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) - { - return waitHandle.WaitOne(millisecondsTimeout); - } - } -#else - internal static class STPEventWaitHandle - { - public const int WaitTimeout = Timeout.Infinite; - - internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); - } - - internal static int WaitAny(WaitHandle[] waitHandles) - { - return WaitHandle.WaitAny(waitHandles); - } - - internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); - } - - internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) - { - return waitHandle.WaitOne(millisecondsTimeout, exitContext); - } - } -#endif - -} - +#if !(_WINDOWS_CE) + +using System; +using System.Threading; + +namespace Amib.Threading.Internal +{ +#if _WINDOWS || WINDOWS_PHONE + internal static class STPEventWaitHandle + { + public const int WaitTimeout = Timeout.Infinite; + + internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAll(waitHandles, millisecondsTimeout); + } + + internal static int WaitAny(WaitHandle[] waitHandles) + { + return WaitHandle.WaitAny(waitHandles); + } + + internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAny(waitHandles, millisecondsTimeout); + } + + internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) + { + return waitHandle.WaitOne(millisecondsTimeout); + } + } +#else + internal static class STPEventWaitHandle + { + public const int WaitTimeout = Timeout.Infinite; + + internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); + } + + internal static int WaitAny(WaitHandle[] waitHandles) + { + return WaitHandle.WaitAny(waitHandles); + } + + internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); + } + + internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) + { + return waitHandle.WaitOne(millisecondsTimeout, exitContext); + } + } +#endif + +} + #endif \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs index 2508661..0663d1d 100644 --- a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs +++ b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs @@ -1,448 +1,448 @@ -using System; -using System.Diagnostics; -using System.Threading; - -namespace Amib.Threading -{ - public interface ISTPPerformanceCountersReader - { - long InUseThreads { get; } - long ActiveThreads { get; } - long WorkItemsQueued { get; } - long WorkItemsProcessed { get; } - } -} - -namespace Amib.Threading.Internal -{ - internal interface ISTPInstancePerformanceCounters : IDisposable - { - void Close(); - void SampleThreads(long activeThreads, long inUseThreads); - void SampleWorkItems(long workItemsQueued, long workItemsProcessed); - void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime); - void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime); - } -#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - - internal enum STPPerformanceCounterType - { - // Fields - ActiveThreads = 0, - InUseThreads = 1, - OverheadThreads = 2, - OverheadThreadsPercent = 3, - OverheadThreadsPercentBase = 4, - - WorkItems = 5, - WorkItemsInQueue = 6, - WorkItemsProcessed = 7, - - WorkItemsQueuedPerSecond = 8, - WorkItemsProcessedPerSecond = 9, - - AvgWorkItemWaitTime = 10, - AvgWorkItemWaitTimeBase = 11, - - AvgWorkItemProcessTime = 12, - AvgWorkItemProcessTimeBase = 13, - - WorkItemsGroups = 14, - - LastCounter = 14, - } - - - /// - /// Summary description for STPPerformanceCounter. - /// - internal class STPPerformanceCounter - { - // Fields - private readonly PerformanceCounterType _pcType; - protected string _counterHelp; - protected string _counterName; - - // Methods - public STPPerformanceCounter( - string counterName, - string counterHelp, - PerformanceCounterType pcType) - { - _counterName = counterName; - _counterHelp = counterHelp; - _pcType = pcType; - } - - public void AddCounterToCollection(CounterCreationDataCollection counterData) - { - CounterCreationData counterCreationData = new CounterCreationData( - _counterName, - _counterHelp, - _pcType); - - counterData.Add(counterCreationData); - } - - // Properties - public string Name - { - get - { - return _counterName; - } - } - } - - internal class STPPerformanceCounters - { - // Fields - internal STPPerformanceCounter[] _stpPerformanceCounters; - private static readonly STPPerformanceCounters _instance; - internal const string _stpCategoryHelp = "SmartThreadPool performance counters"; - internal const string _stpCategoryName = "SmartThreadPool"; - - // Methods - static STPPerformanceCounters() - { - _instance = new STPPerformanceCounters(); - } - - private STPPerformanceCounters() - { - STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] - { - new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction), - new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase), - - new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), - - new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), - new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32), - - new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64), - new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase), - - new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64), - new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase), - - new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), - }; - - _stpPerformanceCounters = stpPerformanceCounters; - SetupCategory(); - } - - private void SetupCategory() - { - if (!PerformanceCounterCategory.Exists(_stpCategoryName)) - { - CounterCreationDataCollection counters = new CounterCreationDataCollection(); - - for (int i = 0; i < _stpPerformanceCounters.Length; i++) - { - _stpPerformanceCounters[i].AddCounterToCollection(counters); - } - - PerformanceCounterCategory.Create( - _stpCategoryName, - _stpCategoryHelp, - PerformanceCounterCategoryType.MultiInstance, - counters); - - } - } - - // Properties - public static STPPerformanceCounters Instance - { - get - { - return _instance; - } - } - } - - internal class STPInstancePerformanceCounter : IDisposable - { - // Fields - private bool _isDisposed; - private PerformanceCounter _pcs; - - // Methods - protected STPInstancePerformanceCounter() - { - _isDisposed = false; - } - - public STPInstancePerformanceCounter( - string instance, - STPPerformanceCounterType spcType) : this() - { - STPPerformanceCounters counters = STPPerformanceCounters.Instance; - _pcs = new PerformanceCounter( - STPPerformanceCounters._stpCategoryName, - counters._stpPerformanceCounters[(int) spcType].Name, - instance, - false); - _pcs.RawValue = _pcs.RawValue; - } - - - public void Close() - { - if (_pcs != null) - { - _pcs.RemoveInstance(); - _pcs.Close(); - _pcs = null; - } - } - - public void Dispose() - { - Dispose(true); - } - - public virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - Close(); - } - } - _isDisposed = true; - } - - public virtual void Increment() - { - _pcs.Increment(); - } - - public virtual void IncrementBy(long val) - { - _pcs.IncrementBy(val); - } - - public virtual void Set(long val) - { - _pcs.RawValue = val; - } - } - - internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter - { - // Methods - public override void Increment() {} - public override void IncrementBy(long value) {} - public override void Set(long val) {} - } - - - - internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters - { - private bool _isDisposed; - // Fields - private STPInstancePerformanceCounter[] _pcs; - private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter; - - // Methods - static STPInstancePerformanceCounters() - { - _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter(); - } - - public STPInstancePerformanceCounters(string instance) - { - _isDisposed = false; - _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter]; - - // Call the STPPerformanceCounters.Instance so the static constructor will - // intialize the STPPerformanceCounters singleton. - STPPerformanceCounters.Instance.GetHashCode(); - - for (int i = 0; i < _pcs.Length; i++) - { - if (instance != null) - { - _pcs[i] = new STPInstancePerformanceCounter( - instance, - (STPPerformanceCounterType) i); - } - else - { - _pcs[i] = _stpInstanceNullPerformanceCounter; - } - } - } - - - public void Close() - { - if (null != _pcs) - { - for (int i = 0; i < _pcs.Length; i++) - { - if (null != _pcs[i]) - { - _pcs[i].Dispose(); - } - } - _pcs = null; - } - } - - public void Dispose() - { - Dispose(true); - } - - public virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - Close(); - } - } - _isDisposed = true; - } - - private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType) - { - return _pcs[(int) spcType]; - } - - public void SampleThreads(long activeThreads, long inUseThreads) - { - GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads); - GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads); - GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads); - - GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads); - GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads); - } - - public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) - { - GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed); - GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued); - GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed); - - GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued); - GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed); - } - - public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) - { - GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds); - GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment(); - } - - public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) - { - GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds); - GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment(); - } - } -#endif - - internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader - { - private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(); - - public static NullSTPInstancePerformanceCounters Instance - { - get { return _instance; } - } - - public void Close() {} - public void Dispose() {} - - public void SampleThreads(long activeThreads, long inUseThreads) {} - public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {} - public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {} - public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {} - public long InUseThreads - { - get { return 0; } - } - - public long ActiveThreads - { - get { return 0; } - } - - public long WorkItemsQueued - { - get { return 0; } - } - - public long WorkItemsProcessed - { - get { return 0; } - } - } - - internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader - { - public void Close() { } - public void Dispose() { } - - private long _activeThreads; - private long _inUseThreads; - private long _workItemsQueued; - private long _workItemsProcessed; - - public long InUseThreads - { - get { return _inUseThreads; } - } - - public long ActiveThreads - { - get { return _activeThreads; } - } - - public long WorkItemsQueued - { - get { return _workItemsQueued; } - } - - public long WorkItemsProcessed - { - get { return _workItemsProcessed; } - } - - public void SampleThreads(long activeThreads, long inUseThreads) - { - _activeThreads = activeThreads; - _inUseThreads = inUseThreads; - } - - public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) - { - _workItemsQueued = workItemsQueued; - _workItemsProcessed = workItemsProcessed; - } - - public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) - { - // Not supported - } - - public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) - { - // Not supported - } - } -} +using System; +using System.Diagnostics; +using System.Threading; + +namespace Amib.Threading +{ + public interface ISTPPerformanceCountersReader + { + long InUseThreads { get; } + long ActiveThreads { get; } + long WorkItemsQueued { get; } + long WorkItemsProcessed { get; } + } +} + +namespace Amib.Threading.Internal +{ + internal interface ISTPInstancePerformanceCounters : IDisposable + { + void Close(); + void SampleThreads(long activeThreads, long inUseThreads); + void SampleWorkItems(long workItemsQueued, long workItemsProcessed); + void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime); + void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime); + } +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + + internal enum STPPerformanceCounterType + { + // Fields + ActiveThreads = 0, + InUseThreads = 1, + OverheadThreads = 2, + OverheadThreadsPercent = 3, + OverheadThreadsPercentBase = 4, + + WorkItems = 5, + WorkItemsInQueue = 6, + WorkItemsProcessed = 7, + + WorkItemsQueuedPerSecond = 8, + WorkItemsProcessedPerSecond = 9, + + AvgWorkItemWaitTime = 10, + AvgWorkItemWaitTimeBase = 11, + + AvgWorkItemProcessTime = 12, + AvgWorkItemProcessTimeBase = 13, + + WorkItemsGroups = 14, + + LastCounter = 14, + } + + + /// + /// Summary description for STPPerformanceCounter. + /// + internal class STPPerformanceCounter + { + // Fields + private readonly PerformanceCounterType _pcType; + protected string _counterHelp; + protected string _counterName; + + // Methods + public STPPerformanceCounter( + string counterName, + string counterHelp, + PerformanceCounterType pcType) + { + _counterName = counterName; + _counterHelp = counterHelp; + _pcType = pcType; + } + + public void AddCounterToCollection(CounterCreationDataCollection counterData) + { + CounterCreationData counterCreationData = new CounterCreationData( + _counterName, + _counterHelp, + _pcType); + + counterData.Add(counterCreationData); + } + + // Properties + public string Name + { + get + { + return _counterName; + } + } + } + + internal class STPPerformanceCounters + { + // Fields + internal STPPerformanceCounter[] _stpPerformanceCounters; + private static readonly STPPerformanceCounters _instance; + internal const string _stpCategoryHelp = "SmartThreadPool performance counters"; + internal const string _stpCategoryName = "SmartThreadPool"; + + // Methods + static STPPerformanceCounters() + { + _instance = new STPPerformanceCounters(); + } + + private STPPerformanceCounters() + { + STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] + { + new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction), + new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase), + + new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), + + new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), + new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32), + + new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64), + new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase), + + new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64), + new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase), + + new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), + }; + + _stpPerformanceCounters = stpPerformanceCounters; + SetupCategory(); + } + + private void SetupCategory() + { + if (!PerformanceCounterCategory.Exists(_stpCategoryName)) + { + CounterCreationDataCollection counters = new CounterCreationDataCollection(); + + for (int i = 0; i < _stpPerformanceCounters.Length; i++) + { + _stpPerformanceCounters[i].AddCounterToCollection(counters); + } + + PerformanceCounterCategory.Create( + _stpCategoryName, + _stpCategoryHelp, + PerformanceCounterCategoryType.MultiInstance, + counters); + + } + } + + // Properties + public static STPPerformanceCounters Instance + { + get + { + return _instance; + } + } + } + + internal class STPInstancePerformanceCounter : IDisposable + { + // Fields + private bool _isDisposed; + private PerformanceCounter _pcs; + + // Methods + protected STPInstancePerformanceCounter() + { + _isDisposed = false; + } + + public STPInstancePerformanceCounter( + string instance, + STPPerformanceCounterType spcType) : this() + { + STPPerformanceCounters counters = STPPerformanceCounters.Instance; + _pcs = new PerformanceCounter( + STPPerformanceCounters._stpCategoryName, + counters._stpPerformanceCounters[(int) spcType].Name, + instance, + false); + _pcs.RawValue = _pcs.RawValue; + } + + + public void Close() + { + if (_pcs != null) + { + _pcs.RemoveInstance(); + _pcs.Close(); + _pcs = null; + } + } + + public void Dispose() + { + Dispose(true); + } + + public virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + Close(); + } + } + _isDisposed = true; + } + + public virtual void Increment() + { + _pcs.Increment(); + } + + public virtual void IncrementBy(long val) + { + _pcs.IncrementBy(val); + } + + public virtual void Set(long val) + { + _pcs.RawValue = val; + } + } + + internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter + { + // Methods + public override void Increment() {} + public override void IncrementBy(long value) {} + public override void Set(long val) {} + } + + + + internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters + { + private bool _isDisposed; + // Fields + private STPInstancePerformanceCounter[] _pcs; + private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter; + + // Methods + static STPInstancePerformanceCounters() + { + _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter(); + } + + public STPInstancePerformanceCounters(string instance) + { + _isDisposed = false; + _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter]; + + // Call the STPPerformanceCounters.Instance so the static constructor will + // intialize the STPPerformanceCounters singleton. + STPPerformanceCounters.Instance.GetHashCode(); + + for (int i = 0; i < _pcs.Length; i++) + { + if (instance != null) + { + _pcs[i] = new STPInstancePerformanceCounter( + instance, + (STPPerformanceCounterType) i); + } + else + { + _pcs[i] = _stpInstanceNullPerformanceCounter; + } + } + } + + + public void Close() + { + if (null != _pcs) + { + for (int i = 0; i < _pcs.Length; i++) + { + if (null != _pcs[i]) + { + _pcs[i].Dispose(); + } + } + _pcs = null; + } + } + + public void Dispose() + { + Dispose(true); + } + + public virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + Close(); + } + } + _isDisposed = true; + } + + private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType) + { + return _pcs[(int) spcType]; + } + + public void SampleThreads(long activeThreads, long inUseThreads) + { + GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads); + GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads); + GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads); + + GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads); + GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads); + } + + public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) + { + GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed); + GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued); + GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed); + + GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued); + GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed); + } + + public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) + { + GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds); + GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment(); + } + + public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) + { + GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds); + GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment(); + } + } +#endif + + internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader + { + private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(); + + public static NullSTPInstancePerformanceCounters Instance + { + get { return _instance; } + } + + public void Close() {} + public void Dispose() {} + + public void SampleThreads(long activeThreads, long inUseThreads) {} + public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {} + public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {} + public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {} + public long InUseThreads + { + get { return 0; } + } + + public long ActiveThreads + { + get { return 0; } + } + + public long WorkItemsQueued + { + get { return 0; } + } + + public long WorkItemsProcessed + { + get { return 0; } + } + } + + internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader + { + public void Close() { } + public void Dispose() { } + + private long _activeThreads; + private long _inUseThreads; + private long _workItemsQueued; + private long _workItemsProcessed; + + public long InUseThreads + { + get { return _inUseThreads; } + } + + public long ActiveThreads + { + get { return _activeThreads; } + } + + public long WorkItemsQueued + { + get { return _workItemsQueued; } + } + + public long WorkItemsProcessed + { + get { return _workItemsProcessed; } + } + + public void SampleThreads(long activeThreads, long inUseThreads) + { + _activeThreads = activeThreads; + _inUseThreads = inUseThreads; + } + + public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) + { + _workItemsQueued = workItemsQueued; + _workItemsProcessed = workItemsProcessed; + } + + public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) + { + // Not supported + } + + public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) + { + // Not supported + } + } +} diff --git a/ThirdParty/SmartThreadPool/STPStartInfo.cs b/ThirdParty/SmartThreadPool/STPStartInfo.cs index 2ec8dc6..96fa094 100644 --- a/ThirdParty/SmartThreadPool/STPStartInfo.cs +++ b/ThirdParty/SmartThreadPool/STPStartInfo.cs @@ -1,212 +1,212 @@ -using System; -using System.Threading; - -namespace Amib.Threading -{ - /// - /// Summary description for STPStartInfo. - /// - public class STPStartInfo : WIGStartInfo - { - private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout; - private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; - private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; -#if !(WINDOWS_PHONE) - private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority; -#endif - private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; - private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground; - private bool _enableLocalPerformanceCounters; - private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName; - private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize; - - public STPStartInfo() - { - _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; -#if !(WINDOWS_PHONE) - _threadPriority = SmartThreadPool.DefaultThreadPriority; -#endif - _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; - _idleTimeout = SmartThreadPool.DefaultIdleTimeout; - _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; - } - - public STPStartInfo(STPStartInfo stpStartInfo) - : base(stpStartInfo) - { - _idleTimeout = stpStartInfo.IdleTimeout; - _minWorkerThreads = stpStartInfo.MinWorkerThreads; - _maxWorkerThreads = stpStartInfo.MaxWorkerThreads; -#if !(WINDOWS_PHONE) - _threadPriority = stpStartInfo.ThreadPriority; -#endif - _performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName; - _enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters; - _threadPoolName = stpStartInfo._threadPoolName; - _areThreadsBackground = stpStartInfo.AreThreadsBackground; -#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) - _apartmentState = stpStartInfo._apartmentState; -#endif - } - - /// - /// Get/Set the idle timeout in milliseconds. - /// If a thread is idle (starved) longer than IdleTimeout then it may quit. - /// - public virtual int IdleTimeout - { - get { return _idleTimeout; } - set - { - ThrowIfReadOnly(); - _idleTimeout = value; - } - } - - - /// - /// Get/Set the lower limit of threads in the pool. - /// - public virtual int MinWorkerThreads - { - get { return _minWorkerThreads; } - set - { - ThrowIfReadOnly(); - _minWorkerThreads = value; - } - } - - - /// - /// Get/Set the upper limit of threads in the pool. - /// - public virtual int MaxWorkerThreads - { - get { return _maxWorkerThreads; } - set - { - ThrowIfReadOnly(); - _maxWorkerThreads = value; - } - } - -#if !(WINDOWS_PHONE) - /// - /// Get/Set the scheduling priority of the threads in the pool. - /// The Os handles the scheduling. - /// - public virtual ThreadPriority ThreadPriority - { - get { return _threadPriority; } - set - { - ThrowIfReadOnly(); - _threadPriority = value; - } - } -#endif - /// - /// Get/Set the thread pool name. Threads will get names depending on this. - /// - public virtual string ThreadPoolName { - get { return _threadPoolName; } - set - { - ThrowIfReadOnly (); - _threadPoolName = value; - } - } - - /// - /// Get/Set the performance counter instance name of this SmartThreadPool - /// The default is null which indicate not to use performance counters at all. - /// - public virtual string PerformanceCounterInstanceName - { - get { return _performanceCounterInstanceName; } - set - { - ThrowIfReadOnly(); - _performanceCounterInstanceName = value; - } - } - - /// - /// Enable/Disable the local performance counter. - /// This enables the user to get some performance information about the SmartThreadPool - /// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.) - /// The default is false. - /// - public virtual bool EnableLocalPerformanceCounters - { - get { return _enableLocalPerformanceCounters; } - set - { - ThrowIfReadOnly(); - _enableLocalPerformanceCounters = value; - } - } - - /// - /// Get/Set backgroundness of thread in thread pool. - /// - public virtual bool AreThreadsBackground - { - get { return _areThreadsBackground; } - set - { - ThrowIfReadOnly (); - _areThreadsBackground = value; - } - } - - /// - /// Get a readonly version of this STPStartInfo. - /// - /// Returns a readonly reference to this STPStartInfo - public new STPStartInfo AsReadOnly() - { - return new STPStartInfo(this) { _readOnly = true }; - } - -#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) - - private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState; - - /// - /// Get/Set the apartment state of threads in the thread pool - /// - public ApartmentState ApartmentState - { - get { return _apartmentState; } - set - { - ThrowIfReadOnly(); - _apartmentState = value; - } - } - -#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) - - /// - /// Get/Set the max stack size of threads in the thread pool - /// - public int? MaxStackSize - { - get { return _maxStackSize; } - set - { - ThrowIfReadOnly(); - if (value.HasValue && value.Value < 0) - { - throw new ArgumentOutOfRangeException("value", "Value must be greater than 0."); - } - _maxStackSize = value; - } - } -#endif - -#endif - } -} +using System; +using System.Threading; + +namespace Amib.Threading +{ + /// + /// Summary description for STPStartInfo. + /// + public class STPStartInfo : WIGStartInfo + { + private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout; + private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; + private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; +#if !(WINDOWS_PHONE) + private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority; +#endif + private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; + private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground; + private bool _enableLocalPerformanceCounters; + private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName; + private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize; + + public STPStartInfo() + { + _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; +#if !(WINDOWS_PHONE) + _threadPriority = SmartThreadPool.DefaultThreadPriority; +#endif + _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; + _idleTimeout = SmartThreadPool.DefaultIdleTimeout; + _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; + } + + public STPStartInfo(STPStartInfo stpStartInfo) + : base(stpStartInfo) + { + _idleTimeout = stpStartInfo.IdleTimeout; + _minWorkerThreads = stpStartInfo.MinWorkerThreads; + _maxWorkerThreads = stpStartInfo.MaxWorkerThreads; +#if !(WINDOWS_PHONE) + _threadPriority = stpStartInfo.ThreadPriority; +#endif + _performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName; + _enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters; + _threadPoolName = stpStartInfo._threadPoolName; + _areThreadsBackground = stpStartInfo.AreThreadsBackground; +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + _apartmentState = stpStartInfo._apartmentState; +#endif + } + + /// + /// Get/Set the idle timeout in milliseconds. + /// If a thread is idle (starved) longer than IdleTimeout then it may quit. + /// + public virtual int IdleTimeout + { + get { return _idleTimeout; } + set + { + ThrowIfReadOnly(); + _idleTimeout = value; + } + } + + + /// + /// Get/Set the lower limit of threads in the pool. + /// + public virtual int MinWorkerThreads + { + get { return _minWorkerThreads; } + set + { + ThrowIfReadOnly(); + _minWorkerThreads = value; + } + } + + + /// + /// Get/Set the upper limit of threads in the pool. + /// + public virtual int MaxWorkerThreads + { + get { return _maxWorkerThreads; } + set + { + ThrowIfReadOnly(); + _maxWorkerThreads = value; + } + } + +#if !(WINDOWS_PHONE) + /// + /// Get/Set the scheduling priority of the threads in the pool. + /// The Os handles the scheduling. + /// + public virtual ThreadPriority ThreadPriority + { + get { return _threadPriority; } + set + { + ThrowIfReadOnly(); + _threadPriority = value; + } + } +#endif + /// + /// Get/Set the thread pool name. Threads will get names depending on this. + /// + public virtual string ThreadPoolName { + get { return _threadPoolName; } + set + { + ThrowIfReadOnly (); + _threadPoolName = value; + } + } + + /// + /// Get/Set the performance counter instance name of this SmartThreadPool + /// The default is null which indicate not to use performance counters at all. + /// + public virtual string PerformanceCounterInstanceName + { + get { return _performanceCounterInstanceName; } + set + { + ThrowIfReadOnly(); + _performanceCounterInstanceName = value; + } + } + + /// + /// Enable/Disable the local performance counter. + /// This enables the user to get some performance information about the SmartThreadPool + /// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.) + /// The default is false. + /// + public virtual bool EnableLocalPerformanceCounters + { + get { return _enableLocalPerformanceCounters; } + set + { + ThrowIfReadOnly(); + _enableLocalPerformanceCounters = value; + } + } + + /// + /// Get/Set backgroundness of thread in thread pool. + /// + public virtual bool AreThreadsBackground + { + get { return _areThreadsBackground; } + set + { + ThrowIfReadOnly (); + _areThreadsBackground = value; + } + } + + /// + /// Get a readonly version of this STPStartInfo. + /// + /// Returns a readonly reference to this STPStartInfo + public new STPStartInfo AsReadOnly() + { + return new STPStartInfo(this) { _readOnly = true }; + } + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + + private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState; + + /// + /// Get/Set the apartment state of threads in the thread pool + /// + public ApartmentState ApartmentState + { + get { return _apartmentState; } + set + { + ThrowIfReadOnly(); + _apartmentState = value; + } + } + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + + /// + /// Get/Set the max stack size of threads in the thread pool + /// + public int? MaxStackSize + { + get { return _maxStackSize; } + set + { + ThrowIfReadOnly(); + if (value.HasValue && value.Value < 0) + { + throw new ArgumentOutOfRangeException("value", "Value must be greater than 0."); + } + _maxStackSize = value; + } + } +#endif + +#endif + } +} diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs index ba7d73f..d9502bb 100644 --- a/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs +++ b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs @@ -1,60 +1,60 @@ - -using System; -using Amib.Threading.Internal; - -namespace Amib.Threading -{ - public partial class SmartThreadPool - { - #region ThreadEntry class - - internal class ThreadEntry - { - /// - /// The thread creation time - /// The value is stored as UTC value. - /// - private readonly DateTime _creationTime; - - /// - /// The last time this thread has been running - /// It is updated by IAmAlive() method - /// The value is stored as UTC value. - /// - private DateTime _lastAliveTime; - - /// - /// A reference from each thread in the thread pool to its SmartThreadPool - /// object container. - /// With this variable a thread can know whatever it belongs to a - /// SmartThreadPool. - /// - private readonly SmartThreadPool _associatedSmartThreadPool; - - /// - /// A reference to the current work item a thread from the thread pool - /// is executing. - /// - public WorkItem CurrentWorkItem { get; set; } - - public ThreadEntry(SmartThreadPool stp) - { - _associatedSmartThreadPool = stp; - _creationTime = DateTime.UtcNow; - _lastAliveTime = DateTime.MinValue; - } - - public SmartThreadPool AssociatedSmartThreadPool - { - get { return _associatedSmartThreadPool; } - } - - public void IAmAlive() - { - _lastAliveTime = DateTime.UtcNow; - } - } - - #endregion - } + +using System; +using Amib.Threading.Internal; + +namespace Amib.Threading +{ + public partial class SmartThreadPool + { + #region ThreadEntry class + + internal class ThreadEntry + { + /// + /// The thread creation time + /// The value is stored as UTC value. + /// + private readonly DateTime _creationTime; + + /// + /// The last time this thread has been running + /// It is updated by IAmAlive() method + /// The value is stored as UTC value. + /// + private DateTime _lastAliveTime; + + /// + /// A reference from each thread in the thread pool to its SmartThreadPool + /// object container. + /// With this variable a thread can know whatever it belongs to a + /// SmartThreadPool. + /// + private readonly SmartThreadPool _associatedSmartThreadPool; + + /// + /// A reference to the current work item a thread from the thread pool + /// is executing. + /// + public WorkItem CurrentWorkItem { get; set; } + + public ThreadEntry(SmartThreadPool stp) + { + _associatedSmartThreadPool = stp; + _creationTime = DateTime.UtcNow; + _lastAliveTime = DateTime.MinValue; + } + + public SmartThreadPool AssociatedSmartThreadPool + { + get { return _associatedSmartThreadPool; } + } + + public void IAmAlive() + { + _lastAliveTime = DateTime.UtcNow; + } + } + + #endregion + } } \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.cs index 9256777..a4f4ce5 100644 --- a/ThirdParty/SmartThreadPool/SmartThreadPool.cs +++ b/ThirdParty/SmartThreadPool/SmartThreadPool.cs @@ -1,1732 +1,1732 @@ -#region Release History - -// Smart Thread Pool -// 7 Aug 2004 - Initial release -// -// 14 Sep 2004 - Bug fixes -// -// 15 Oct 2004 - Added new features -// - Work items return result. -// - Support waiting synchronization for multiple work items. -// - Work items can be cancelled. -// - Passage of the caller thread’s context to the thread in the pool. -// - Minimal usage of WIN32 handles. -// - Minor bug fixes. -// -// 26 Dec 2004 - Changes: -// - Removed static constructors. -// - 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. -// 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 -// is rethrown at GetResult(), rather then firing an UnhandledException event. -// Note that PostExecute exception are always ignored. -// -// 25 Mar 2005 - Changes: -// - Fixed lost of work items bug -// -// 3 Jul 2005: Changes. -// - 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. -// -// 31 Jan 2006 - Changes: -// - Added work items priority -// - Removed support of chained delegates in callbacks and post executes (nobody really use this) -// - Added work items groups -// - Added work items groups idle event -// - 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 -// inner exception -// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) -// - Added performance counters -// - Added priority to the threads in the pool -// -// 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 -// 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. -// - Improved the cancel behavior. -// - 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 -// - Added support for WinCE -// - Added support for Action and Func -// -// 07 April 2009 - Changes: -// - Added support for Silverlight and Mono -// - Added Join, Choice, and Pipe to SmartThreadPool. -// - Added local performance counters (for Mono, Silverlight, and WindowsCE) -// - Changed duration measures from DateTime.Now to Stopwatch. -// - Queues changed from System.Collections.Queue to System.Collections.Generic.LinkedList. -// -// 21 December 2009 - Changes: -// - Added work item timeout (passive) -// -// 20 August 2012 - Changes: -// - Added set name to threads -// - Fixed the WorkItemsQueue.Dequeue. -// Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... } -// - Fixed SmartThreadPool.Pipe -// - Added IsBackground option to threads -// - Added ApartmentState to threads -// - Fixed thread creation when queuing many work items at the same time. -// -// 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 - -#endregion - -using System; -using System.Security; -using System.Threading; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -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; - - /// - /// The default option to run the post execute (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 work item priority (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 name to use for the performance counters instance. (null) - /// - public static readonly string DefaultPerformanceCounterInstanceName; - -#if !(WINDOWS_PHONE) - - /// - /// The default thread priority (ThreadPriority.Normal) - /// - public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; -#endif - /// - /// The default thread pool name. (SmartThreadPool) - /// - public const string DefaultThreadPoolName = "SmartThreadPool"; - - /// - /// The default Max Stack Size. (SmartThreadPool) - /// - public static readonly int? DefaultMaxStackSize = null; - - /// - /// The default fill state with params. (false) - /// It is relevant only to QueueWorkItem of Action<...>/Func<...> - /// - public const bool DefaultFillStateWithArgs = false; - - /// - /// The default thread backgroundness. (true) - /// - public const bool DefaultAreThreadsBackground = true; - -#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 - /// set the apartment of the thread. It will use the .NET default. - /// - public const ApartmentState DefaultApartmentState = ApartmentState.Unknown; -#endif - - #endregion - - #region Member Variables - - /// - /// 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(); - - /// - /// Count the work items handled. - /// Used by the performance counter. - /// - private int _workItemsProcessed; - - /// - /// Number of threads that currently work (not idle). - /// - private int _inUseWorkerThreads; - - /// - /// Stores a copy of the original STPStartInfo. - /// It is used to change the MinThread and MaxThreads - /// - 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; - - /// - /// 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); - - /// - /// 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 - /// - private readonly SynchronizedDictionary _workItemsGroups = new SynchronizedDictionary(); - - /// - /// A common object for all the work items int the STP - /// so we can mark them to cancel in O(1) - /// - private CanceledWorkItemsGroup _canceledSmartThreadPool = new CanceledWorkItemsGroup(); - - /// - /// Windows STP performance counters - /// - private ISTPInstancePerformanceCounters _windowsPCs = NullSTPInstancePerformanceCounters.Instance; - - /// - /// Local STP performance counters - /// - private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance; - - -#if (WINDOWS_PHONE) - private static readonly Dictionary _threadEntries = new Dictionary(); -#elif (_WINDOWS_CE) - private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot(); -#else - [ThreadStatic] - private static ThreadEntry _threadEntry; - -#endif - - /// - /// 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 - /// it is no longer belong to the pool. - /// - private event ThreadTerminationHandler _onThreadTermination; - - #endregion - - #region Per thread properties - - /// - /// A reference to the current work item a thread from the thread pool - /// is executing. - /// - internal static ThreadEntry CurrentThreadEntry - { -#if (WINDOWS_PHONE) - get - { - lock(_threadEntries) - { - ThreadEntry threadEntry; - if (_threadEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadEntry)) - { - return threadEntry; - } - } - return null; - } - set - { - lock(_threadEntries) - { - _threadEntries[Thread.CurrentThread.ManagedThreadId] = value; - } - } -#elif (_WINDOWS_CE) - get - { - //Thread.CurrentThread.ManagedThreadId - return Thread.GetData(_threadEntrySlot) as ThreadEntry; - } - set - { - Thread.SetData(_threadEntrySlot, value); - } -#else - get - { - return _threadEntry; - } - set - { - _threadEntry = value; - } -#endif - } - #endregion - - #region Construction and Finalization - - /// - /// Constructor - /// - public SmartThreadPool() - { - _stpStartInfo = new STPStartInfo(); - Initialize(); - } - - /// - /// 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) - { - _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) - { - _stpStartInfo = new STPStartInfo - { - IdleTimeout = idleTimeout, - MaxWorkerThreads = maxWorkerThreads, - MinWorkerThreads = minWorkerThreads, - }; - Initialize(); - } - - /// - /// Constructor - /// - /// A SmartThreadPool configuration that overrides the default behavior - public SmartThreadPool(STPStartInfo stpStartInfo) - { - _stpStartInfo = new STPStartInfo(stpStartInfo); - Initialize(); - } - - private void Initialize() - { - Name = _stpStartInfo.ThreadPoolName; - ValidateSTPStartInfo(); - - // _stpStartInfoRW stores a read/write copy of the STPStartInfo. - // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten - - _isSuspended = _stpStartInfo.StartSuspended; - -#if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE) - if (null != _stpStartInfo.PerformanceCounterInstanceName) - { - throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters"); - } -#else - if (null != _stpStartInfo.PerformanceCounterInstanceName) - { - try - { - _windowsPCs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName); - } - catch (Exception e) - { - Debug.WriteLine("Unable to create Performance Counters: " + e); - _windowsPCs = NullSTPInstancePerformanceCounters.Instance; - } - } -#endif - - if (_stpStartInfo.EnableLocalPerformanceCounters) - { - _localPCs = new LocalSTPInstancePerformanceCounters(); - } - - // 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); - threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads); - threadsCount -= _workerThreads.Count; - if (threadsCount > 0) - { - StartThreads(threadsCount); - } - } - - private void ValidateSTPStartInfo() - { - if (_stpStartInfo.MinWorkerThreads < 0) - { - throw new ArgumentOutOfRangeException( - "MinWorkerThreads", "MinWorkerThreads cannot be negative"); - } - - if (_stpStartInfo.MaxWorkerThreads <= 0) - { - 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 = - _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); - - 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); - - 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); - _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); - - int count = Interlocked.Increment(ref _currentWorkItemsCount); - //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); - if (count == 1) - { - IsIdle = false; - _isIdleWaitHandle.Reset(); - } - } - - private void DecrementWorkItemsCount() - { - int count = Interlocked.Decrement(ref _currentWorkItemsCount); - //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); - if (count == 0) - { - IsIdle = true; - _isIdleWaitHandle.Set(); - } - - Interlocked.Increment(ref _workItemsProcessed); - - if (!_shutdown) - { - // 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); - _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); - } - } - - /// - /// 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 - if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) - { - return; - } - - // Create a new thread - -#if (_SILVERLIGHT) || (WINDOWS_PHONE) - 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 - workerThread.Name = "STP " + Name + " Thread #" + _threadCounter; - workerThread.IsBackground = _stpStartInfo.AreThreadsBackground; - -#if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE) - if (_stpStartInfo.ApartmentState != ApartmentState.Unknown) - { - workerThread.SetApartmentState(_stpStartInfo.ApartmentState); - } -#endif - -#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) - workerThread.Priority = _stpStartInfo.ThreadPriority; -#endif - workerThread.Start(); - ++_threadCounter; - - // Add it to the dictionary and update its creation time. - _workerThreads[workerThread] = new ThreadEntry(this); - - _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() - { - // 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; - - // 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 - // incremented by the user at run-time. - // Double lock for quit. - if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) - { - lock (_workerThreads.SyncRoot) - { - if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) - { - // 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; - } - } - } - - // 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. - CurrentThreadEntry.IAmAlive(); - - // On timeout or shut down. - if (null == workItem) - { - // Double lock for quit. - if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) - { - 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; - - // 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 - // states. - // 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); - _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); - - // Mark that the _inUseWorkerThreads incremented, so in the finally{} - // statement we will decrement it correctly. - bInUseWorkerThreadsWasIncremented = true; - - workItem.FireWorkItemStarted(); - - 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. - 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); - _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) - { - tae.GetHashCode(); - // Handle the abort exception gracfully. -#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - Thread.ResetAbort(); -#endif - } - catch(Exception e) - { - Debug.Assert(null != e); - } - finally - { - InformCompleted(); - FireOnThreadTermination(); - } - } - - private void ExecuteWorkItem(WorkItem workItem) - { - _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); - _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); - try - { - workItem.Execute(); - } - finally - { - _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); - _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); - } - } - - - #endregion - - #region Public Methods - - 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) - { - if (null == CurrentThreadEntry) - { - return; - } - - WorkItem workItem = CurrentThreadEntry.CurrentWorkItem; - ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem); - 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); - } - - /// - /// Force the SmartThreadPool to shutdown with timeout - /// - public void Shutdown(bool forceAbort, TimeSpan timeout) - { - 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(); - - ISTPInstancePerformanceCounters pcs = _windowsPCs; - - 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(); - - // 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); - } - - 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 - //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 !(_WINDOWS_CE) - && thread.IsAlive -#endif - ) - { - try - { - thread.Abort(); // Shutdown - } - catch(SecurityException e) - { - e.GetHashCode(); - } - 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 - /// - /// Array of work item result objects - /// - /// 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 - /// - /// 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) - { - return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext); - } - - /// - /// 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) - { - return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } - - /// - /// 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) - { - return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null); - } - - /// - /// 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) - { - return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); - } - - - /// - /// 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) - { - return WaitAny(waitableResults, Timeout.Infinite, true); - } - - /// - /// 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( - IWaitableResult[] waitableResults, - 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 - /// - /// 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) - { - return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } - - /// - /// 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) - { - return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null); - } - - /// - /// 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) - { - 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) - { - IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo); - return workItemsGroup; - } - - /// - /// Creates a new WorkItemsGroup. - /// - /// 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; - } - - #region Fire Thread's Events - - private void FireOnThreadInitialization() - { - if (null != _onThreadInitialization) - { - foreach (ThreadInitializationHandler tih in _onThreadInitialization.GetInvocationList()) - { - try - { - tih(); - } - catch (Exception e) - { - e.GetHashCode(); - Debug.Assert(false); - throw; - } - } - } - } - - private void FireOnThreadTermination() - { - if (null != _onThreadTermination) - { - foreach (ThreadTerminationHandler tth in _onThreadTermination.GetInvocationList()) - { - try - { - tth(); - } - catch (Exception e) - { - e.GetHashCode(); - Debug.Assert(false); - throw; - } - } - } - } - - #endregion - - /// - /// This event is fired when a thread is created. - /// Use it to initialize a thread before the work items use it. - /// - public event ThreadInitializationHandler OnThreadInitialization - { - add { _onThreadInitialization += value; } - remove { _onThreadInitialization -= value; } - } - - /// - /// This event is fired when a thread is terminating. - /// Use it for cleanup. - /// - public event ThreadTerminationHandler OnThreadTermination - { - add { _onThreadTermination += value; } - remove { _onThreadTermination -= value; } - } - - - internal void CancelAbortWorkItemsGroup(WorkItemsGroup wig) - { - foreach (ThreadEntry threadEntry in _workerThreads.Values) - { - WorkItem workItem = threadEntry.CurrentWorkItem; - if (null != workItem && - workItem.WasQueuedBy(wig) && - !workItem.IsCanceled) - { - threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); - } - } - } - - - - #endregion - - #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); - Debug.Assert(value <= _stpStartInfo.MaxWorkerThreads); - if (_stpStartInfo.MaxWorkerThreads < value) - { - _stpStartInfo.MaxWorkerThreads = value; - } - _stpStartInfo.MinWorkerThreads = value; - StartOptimalNumberOfThreads(); - } - } - - /// - /// 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) - { - _stpStartInfo.MinWorkerThreads = value; - } - _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; - } - } - - /// - /// Returns true if the current running work item has been cancelled. - /// Must be used within the work item's callback method. - /// The work item should sample this value in order to know if it - /// needs to quit before its completion. - /// - public static bool IsWorkItemCanceled - { - get - { - 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 - /// - public static void AbortOnWorkItemCancel() - { - if (IsWorkItemCanceled) - { - Thread.CurrentThread.Abort(); - } - } - - /// - /// Thread Pool start information (readonly) - /// - public STPStartInfo STPStartInfo - { - get - { - return _stpStartInfo.AsReadOnly(); - } - } - - public bool IsShuttingdown - { - get { return _shutdown; } - } - - /// - /// Return the local calculated performance counters - /// Available only if STPStartInfo.EnableLocalPerformanceCounters is true. - /// - public ISTPPerformanceCountersReader PerformanceCountersReader - { - get { return (ISTPPerformanceCountersReader)_localPCs; } - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - if (!_isDisposed) - { - if (!_shutdown) - { - Shutdown(); - } - - if (null != _shuttingDownEvent) - { - _shuttingDownEvent.Close(); - _shuttingDownEvent = null; - } - _workerThreads.Clear(); - - if (null != _isIdleWaitHandle) - { - _isIdleWaitHandle.Close(); - _isIdleWaitHandle = null; - } - - _isDisposed = true; - } - } - - private void ValidateNotDisposed() - { - if(_isDisposed) - { - throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); - } - } - #endregion - - #region WorkItemsGroupBase Overrides - - /// - /// 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 an array with all the state objects of the currently running items. - /// The array represents a snap shot and impact performance. - /// - public override object[] GetStates() - { - object[] states = _workItemsQueue.GetStates(); - return states; - } - - /// - /// WorkItemsGroup start information (readonly) - /// - public override WIGStartInfo WIGStartInfo - { - get { return _stpStartInfo.AsReadOnly(); } - } - - /// - /// Start the thread pool if it was started suspended. - /// If it is already running, this method is ignored. - /// - public override void Start() - { - if (!_isSuspended) - { - return; - } - _isSuspended = false; - - ICollection workItemsGroups = _workItemsGroups.Values; - foreach (WorkItemsGroup workItemsGroup in workItemsGroups) - { - workItemsGroup.OnSTPIsStarting(); - } - - StartOptimalNumberOfThreads(); - } - - /// - /// Cancel all work items using thread abortion - /// - /// True to stop work items by raising ThreadAbortException - public override void Cancel(bool abortExecution) - { - _canceledSmartThreadPool.IsCanceled = true; - _canceledSmartThreadPool = new CanceledWorkItemsGroup(); - - ICollection workItemsGroups = _workItemsGroups.Values; - foreach (WorkItemsGroup workItemsGroup in workItemsGroups) - { - workItemsGroup.Cancel(abortExecution); - } - - if (abortExecution) - { - foreach (ThreadEntry threadEntry in _workerThreads.Values) - { - WorkItem workItem = threadEntry.CurrentWorkItem; - if (null != workItem && - threadEntry.AssociatedSmartThreadPool == this && - !workItem.IsCanceled) - { - threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); - } - } - } - } - - /// - /// Wait for the thread pool to be idle - /// - public override bool WaitForIdle(int millisecondsTimeout) - { - ValidateWaitForIdle(); - return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); - } - - /// - /// This event is fired when all work items are completed. - /// (When IsIdle changes to true) - /// This event only work on WorkItemsGroup. On SmartThreadPool - /// it throws the NotImplementedException. - /// - public override event WorkItemsGroupIdleHandler OnIdle - { - add - { - throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); - //_onIdle += value; - } - remove - { - throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); - //_onIdle -= value; - } - } - - internal override void PreQueueWorkItem() - { - ValidateNotDisposed(); - } - - #endregion - - #region Join, Choice, Pipe, etc. - - /// - /// Executes all actions in parallel. - /// Returns when they all finish. - /// - /// Actions to execute - public void Join(IEnumerable actions) - { - WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; - IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); - foreach (Action action in actions) - { - workItemsGroup.QueueWorkItem(action); - } - workItemsGroup.Start(); - workItemsGroup.WaitForIdle(); - } - - /// - /// Executes all actions in parallel. - /// Returns when they all finish. - /// - /// Actions to execute - public void Join(params Action[] actions) - { - Join((IEnumerable)actions); - } - - private class ChoiceIndex - { - public int _index = -1; - } - - /// - /// Executes all actions in parallel - /// Returns when the first one completes - /// - /// Actions to execute - public int Choice(IEnumerable actions) - { - WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; - IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); - - ManualResetEvent anActionCompleted = new ManualResetEvent(false); - - ChoiceIndex choiceIndex = new ChoiceIndex(); - - int i = 0; - foreach (Action action in actions) - { - Action act = action; - int value = i; - workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); }); - ++i; - } - workItemsGroup.Start(); - anActionCompleted.WaitOne(); - - return choiceIndex._index; - } - - /// - /// Executes all actions in parallel - /// Returns when the first one completes - /// - /// Actions to execute - public int Choice(params Action[] actions) - { - return Choice((IEnumerable)actions); - } - - /// - /// Executes actions in sequence asynchronously. - /// Returns immediately. - /// - /// A state context that passes - /// Actions to execute in the order they should run - public void Pipe(T pipeState, IEnumerable> actions) - { - WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; - IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(1, wigStartInfo); - foreach (Action action in actions) - { - Action act = action; - workItemsGroup.QueueWorkItem(() => act(pipeState)); - } - workItemsGroup.Start(); - workItemsGroup.WaitForIdle(); - } - - /// - /// Executes actions in sequence asynchronously. - /// Returns immediately. - /// - /// - /// Actions to execute in the order they should run - public void Pipe(T pipeState, params Action[] actions) - { - Pipe(pipeState, (IEnumerable>)actions); - } - #endregion - } - #endregion -} +#region Release History + +// Smart Thread Pool +// 7 Aug 2004 - Initial release +// +// 14 Sep 2004 - Bug fixes +// +// 15 Oct 2004 - Added new features +// - Work items return result. +// - Support waiting synchronization for multiple work items. +// - Work items can be cancelled. +// - Passage of the caller thread’s context to the thread in the pool. +// - Minimal usage of WIN32 handles. +// - Minor bug fixes. +// +// 26 Dec 2004 - Changes: +// - Removed static constructors. +// - 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. +// 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 +// is rethrown at GetResult(), rather then firing an UnhandledException event. +// Note that PostExecute exception are always ignored. +// +// 25 Mar 2005 - Changes: +// - Fixed lost of work items bug +// +// 3 Jul 2005: Changes. +// - 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. +// +// 31 Jan 2006 - Changes: +// - Added work items priority +// - Removed support of chained delegates in callbacks and post executes (nobody really use this) +// - Added work items groups +// - Added work items groups idle event +// - 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 +// inner exception +// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) +// - Added performance counters +// - Added priority to the threads in the pool +// +// 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 +// 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. +// - Improved the cancel behavior. +// - 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 +// - Added support for WinCE +// - Added support for Action and Func +// +// 07 April 2009 - Changes: +// - Added support for Silverlight and Mono +// - Added Join, Choice, and Pipe to SmartThreadPool. +// - Added local performance counters (for Mono, Silverlight, and WindowsCE) +// - Changed duration measures from DateTime.Now to Stopwatch. +// - Queues changed from System.Collections.Queue to System.Collections.Generic.LinkedList. +// +// 21 December 2009 - Changes: +// - Added work item timeout (passive) +// +// 20 August 2012 - Changes: +// - Added set name to threads +// - Fixed the WorkItemsQueue.Dequeue. +// Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... } +// - Fixed SmartThreadPool.Pipe +// - Added IsBackground option to threads +// - Added ApartmentState to threads +// - Fixed thread creation when queuing many work items at the same time. +// +// 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 + +#endregion + +using System; +using System.Security; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +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; + + /// + /// The default option to run the post execute (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 work item priority (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 name to use for the performance counters instance. (null) + /// + public static readonly string DefaultPerformanceCounterInstanceName; + +#if !(WINDOWS_PHONE) + + /// + /// The default thread priority (ThreadPriority.Normal) + /// + public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; +#endif + /// + /// The default thread pool name. (SmartThreadPool) + /// + public const string DefaultThreadPoolName = "SmartThreadPool"; + + /// + /// The default Max Stack Size. (SmartThreadPool) + /// + public static readonly int? DefaultMaxStackSize = null; + + /// + /// The default fill state with params. (false) + /// It is relevant only to QueueWorkItem of Action<...>/Func<...> + /// + public const bool DefaultFillStateWithArgs = false; + + /// + /// The default thread backgroundness. (true) + /// + public const bool DefaultAreThreadsBackground = true; + +#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 + /// set the apartment of the thread. It will use the .NET default. + /// + public const ApartmentState DefaultApartmentState = ApartmentState.Unknown; +#endif + + #endregion + + #region Member Variables + + /// + /// 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(); + + /// + /// Count the work items handled. + /// Used by the performance counter. + /// + private int _workItemsProcessed; + + /// + /// Number of threads that currently work (not idle). + /// + private int _inUseWorkerThreads; + + /// + /// Stores a copy of the original STPStartInfo. + /// It is used to change the MinThread and MaxThreads + /// + 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; + + /// + /// 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); + + /// + /// 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 + /// + private readonly SynchronizedDictionary _workItemsGroups = new SynchronizedDictionary(); + + /// + /// A common object for all the work items int the STP + /// so we can mark them to cancel in O(1) + /// + private CanceledWorkItemsGroup _canceledSmartThreadPool = new CanceledWorkItemsGroup(); + + /// + /// Windows STP performance counters + /// + private ISTPInstancePerformanceCounters _windowsPCs = NullSTPInstancePerformanceCounters.Instance; + + /// + /// Local STP performance counters + /// + private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance; + + +#if (WINDOWS_PHONE) + private static readonly Dictionary _threadEntries = new Dictionary(); +#elif (_WINDOWS_CE) + private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot(); +#else + [ThreadStatic] + private static ThreadEntry _threadEntry; + +#endif + + /// + /// 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 + /// it is no longer belong to the pool. + /// + private event ThreadTerminationHandler _onThreadTermination; + + #endregion + + #region Per thread properties + + /// + /// A reference to the current work item a thread from the thread pool + /// is executing. + /// + internal static ThreadEntry CurrentThreadEntry + { +#if (WINDOWS_PHONE) + get + { + lock(_threadEntries) + { + ThreadEntry threadEntry; + if (_threadEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadEntry)) + { + return threadEntry; + } + } + return null; + } + set + { + lock(_threadEntries) + { + _threadEntries[Thread.CurrentThread.ManagedThreadId] = value; + } + } +#elif (_WINDOWS_CE) + get + { + //Thread.CurrentThread.ManagedThreadId + return Thread.GetData(_threadEntrySlot) as ThreadEntry; + } + set + { + Thread.SetData(_threadEntrySlot, value); + } +#else + get + { + return _threadEntry; + } + set + { + _threadEntry = value; + } +#endif + } + #endregion + + #region Construction and Finalization + + /// + /// Constructor + /// + public SmartThreadPool() + { + _stpStartInfo = new STPStartInfo(); + Initialize(); + } + + /// + /// 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) + { + _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) + { + _stpStartInfo = new STPStartInfo + { + IdleTimeout = idleTimeout, + MaxWorkerThreads = maxWorkerThreads, + MinWorkerThreads = minWorkerThreads, + }; + Initialize(); + } + + /// + /// Constructor + /// + /// A SmartThreadPool configuration that overrides the default behavior + public SmartThreadPool(STPStartInfo stpStartInfo) + { + _stpStartInfo = new STPStartInfo(stpStartInfo); + Initialize(); + } + + private void Initialize() + { + Name = _stpStartInfo.ThreadPoolName; + ValidateSTPStartInfo(); + + // _stpStartInfoRW stores a read/write copy of the STPStartInfo. + // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten + + _isSuspended = _stpStartInfo.StartSuspended; + +#if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE) + if (null != _stpStartInfo.PerformanceCounterInstanceName) + { + throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters"); + } +#else + if (null != _stpStartInfo.PerformanceCounterInstanceName) + { + try + { + _windowsPCs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName); + } + catch (Exception e) + { + Debug.WriteLine("Unable to create Performance Counters: " + e); + _windowsPCs = NullSTPInstancePerformanceCounters.Instance; + } + } +#endif + + if (_stpStartInfo.EnableLocalPerformanceCounters) + { + _localPCs = new LocalSTPInstancePerformanceCounters(); + } + + // 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); + threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads); + threadsCount -= _workerThreads.Count; + if (threadsCount > 0) + { + StartThreads(threadsCount); + } + } + + private void ValidateSTPStartInfo() + { + if (_stpStartInfo.MinWorkerThreads < 0) + { + throw new ArgumentOutOfRangeException( + "MinWorkerThreads", "MinWorkerThreads cannot be negative"); + } + + if (_stpStartInfo.MaxWorkerThreads <= 0) + { + 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 = + _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); + + 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); + + 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); + _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + + int count = Interlocked.Increment(ref _currentWorkItemsCount); + //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); + if (count == 1) + { + IsIdle = false; + _isIdleWaitHandle.Reset(); + } + } + + private void DecrementWorkItemsCount() + { + int count = Interlocked.Decrement(ref _currentWorkItemsCount); + //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); + if (count == 0) + { + IsIdle = true; + _isIdleWaitHandle.Set(); + } + + Interlocked.Increment(ref _workItemsProcessed); + + if (!_shutdown) + { + // 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); + _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + } + } + + /// + /// 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 + if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) + { + return; + } + + // Create a new thread + +#if (_SILVERLIGHT) || (WINDOWS_PHONE) + 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 + workerThread.Name = "STP " + Name + " Thread #" + _threadCounter; + workerThread.IsBackground = _stpStartInfo.AreThreadsBackground; + +#if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE) + if (_stpStartInfo.ApartmentState != ApartmentState.Unknown) + { + workerThread.SetApartmentState(_stpStartInfo.ApartmentState); + } +#endif + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + workerThread.Priority = _stpStartInfo.ThreadPriority; +#endif + workerThread.Start(); + ++_threadCounter; + + // Add it to the dictionary and update its creation time. + _workerThreads[workerThread] = new ThreadEntry(this); + + _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() + { + // 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; + + // 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 + // incremented by the user at run-time. + // Double lock for quit. + if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) + { + lock (_workerThreads.SyncRoot) + { + if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) + { + // 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; + } + } + } + + // 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. + CurrentThreadEntry.IAmAlive(); + + // On timeout or shut down. + if (null == workItem) + { + // Double lock for quit. + if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) + { + 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; + + // 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 + // states. + // 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); + _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + + // Mark that the _inUseWorkerThreads incremented, so in the finally{} + // statement we will decrement it correctly. + bInUseWorkerThreadsWasIncremented = true; + + workItem.FireWorkItemStarted(); + + 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. + 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); + _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) + { + tae.GetHashCode(); + // Handle the abort exception gracfully. +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + Thread.ResetAbort(); +#endif + } + catch(Exception e) + { + Debug.Assert(null != e); + } + finally + { + InformCompleted(); + FireOnThreadTermination(); + } + } + + private void ExecuteWorkItem(WorkItem workItem) + { + _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); + _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); + try + { + workItem.Execute(); + } + finally + { + _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); + _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); + } + } + + + #endregion + + #region Public Methods + + 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) + { + if (null == CurrentThreadEntry) + { + return; + } + + WorkItem workItem = CurrentThreadEntry.CurrentWorkItem; + ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem); + 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); + } + + /// + /// Force the SmartThreadPool to shutdown with timeout + /// + public void Shutdown(bool forceAbort, TimeSpan timeout) + { + 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(); + + ISTPInstancePerformanceCounters pcs = _windowsPCs; + + 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(); + + // 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); + } + + 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 + //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 !(_WINDOWS_CE) + && thread.IsAlive +#endif + ) + { + try + { + thread.Abort(); // Shutdown + } + catch(SecurityException e) + { + e.GetHashCode(); + } + 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 + /// + /// Array of work item result objects + /// + /// 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 + /// + /// 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) + { + return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext); + } + + /// + /// 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) + { + return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); + } + + /// + /// 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) + { + return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null); + } + + /// + /// 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) + { + return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); + } + + + /// + /// 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) + { + return WaitAny(waitableResults, Timeout.Infinite, true); + } + + /// + /// 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( + IWaitableResult[] waitableResults, + 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 + /// + /// 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) + { + return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); + } + + /// + /// 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) + { + return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null); + } + + /// + /// 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) + { + 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) + { + IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo); + return workItemsGroup; + } + + /// + /// Creates a new WorkItemsGroup. + /// + /// 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; + } + + #region Fire Thread's Events + + private void FireOnThreadInitialization() + { + if (null != _onThreadInitialization) + { + foreach (ThreadInitializationHandler tih in _onThreadInitialization.GetInvocationList()) + { + try + { + tih(); + } + catch (Exception e) + { + e.GetHashCode(); + Debug.Assert(false); + throw; + } + } + } + } + + private void FireOnThreadTermination() + { + if (null != _onThreadTermination) + { + foreach (ThreadTerminationHandler tth in _onThreadTermination.GetInvocationList()) + { + try + { + tth(); + } + catch (Exception e) + { + e.GetHashCode(); + Debug.Assert(false); + throw; + } + } + } + } + + #endregion + + /// + /// This event is fired when a thread is created. + /// Use it to initialize a thread before the work items use it. + /// + public event ThreadInitializationHandler OnThreadInitialization + { + add { _onThreadInitialization += value; } + remove { _onThreadInitialization -= value; } + } + + /// + /// This event is fired when a thread is terminating. + /// Use it for cleanup. + /// + public event ThreadTerminationHandler OnThreadTermination + { + add { _onThreadTermination += value; } + remove { _onThreadTermination -= value; } + } + + + internal void CancelAbortWorkItemsGroup(WorkItemsGroup wig) + { + foreach (ThreadEntry threadEntry in _workerThreads.Values) + { + WorkItem workItem = threadEntry.CurrentWorkItem; + if (null != workItem && + workItem.WasQueuedBy(wig) && + !workItem.IsCanceled) + { + threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); + } + } + } + + + + #endregion + + #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); + Debug.Assert(value <= _stpStartInfo.MaxWorkerThreads); + if (_stpStartInfo.MaxWorkerThreads < value) + { + _stpStartInfo.MaxWorkerThreads = value; + } + _stpStartInfo.MinWorkerThreads = value; + StartOptimalNumberOfThreads(); + } + } + + /// + /// 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) + { + _stpStartInfo.MinWorkerThreads = value; + } + _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; + } + } + + /// + /// Returns true if the current running work item has been cancelled. + /// Must be used within the work item's callback method. + /// The work item should sample this value in order to know if it + /// needs to quit before its completion. + /// + public static bool IsWorkItemCanceled + { + get + { + 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 + /// + public static void AbortOnWorkItemCancel() + { + if (IsWorkItemCanceled) + { + Thread.CurrentThread.Abort(); + } + } + + /// + /// Thread Pool start information (readonly) + /// + public STPStartInfo STPStartInfo + { + get + { + return _stpStartInfo.AsReadOnly(); + } + } + + public bool IsShuttingdown + { + get { return _shutdown; } + } + + /// + /// Return the local calculated performance counters + /// Available only if STPStartInfo.EnableLocalPerformanceCounters is true. + /// + public ISTPPerformanceCountersReader PerformanceCountersReader + { + get { return (ISTPPerformanceCountersReader)_localPCs; } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!_isDisposed) + { + if (!_shutdown) + { + Shutdown(); + } + + if (null != _shuttingDownEvent) + { + _shuttingDownEvent.Close(); + _shuttingDownEvent = null; + } + _workerThreads.Clear(); + + if (null != _isIdleWaitHandle) + { + _isIdleWaitHandle.Close(); + _isIdleWaitHandle = null; + } + + _isDisposed = true; + } + } + + private void ValidateNotDisposed() + { + if(_isDisposed) + { + throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); + } + } + #endregion + + #region WorkItemsGroupBase Overrides + + /// + /// 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 an array with all the state objects of the currently running items. + /// The array represents a snap shot and impact performance. + /// + public override object[] GetStates() + { + object[] states = _workItemsQueue.GetStates(); + return states; + } + + /// + /// WorkItemsGroup start information (readonly) + /// + public override WIGStartInfo WIGStartInfo + { + get { return _stpStartInfo.AsReadOnly(); } + } + + /// + /// Start the thread pool if it was started suspended. + /// If it is already running, this method is ignored. + /// + public override void Start() + { + if (!_isSuspended) + { + return; + } + _isSuspended = false; + + ICollection workItemsGroups = _workItemsGroups.Values; + foreach (WorkItemsGroup workItemsGroup in workItemsGroups) + { + workItemsGroup.OnSTPIsStarting(); + } + + StartOptimalNumberOfThreads(); + } + + /// + /// Cancel all work items using thread abortion + /// + /// True to stop work items by raising ThreadAbortException + public override void Cancel(bool abortExecution) + { + _canceledSmartThreadPool.IsCanceled = true; + _canceledSmartThreadPool = new CanceledWorkItemsGroup(); + + ICollection workItemsGroups = _workItemsGroups.Values; + foreach (WorkItemsGroup workItemsGroup in workItemsGroups) + { + workItemsGroup.Cancel(abortExecution); + } + + if (abortExecution) + { + foreach (ThreadEntry threadEntry in _workerThreads.Values) + { + WorkItem workItem = threadEntry.CurrentWorkItem; + if (null != workItem && + threadEntry.AssociatedSmartThreadPool == this && + !workItem.IsCanceled) + { + threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); + } + } + } + } + + /// + /// Wait for the thread pool to be idle + /// + public override bool WaitForIdle(int millisecondsTimeout) + { + ValidateWaitForIdle(); + return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); + } + + /// + /// This event is fired when all work items are completed. + /// (When IsIdle changes to true) + /// This event only work on WorkItemsGroup. On SmartThreadPool + /// it throws the NotImplementedException. + /// + public override event WorkItemsGroupIdleHandler OnIdle + { + add + { + throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); + //_onIdle += value; + } + remove + { + throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); + //_onIdle -= value; + } + } + + internal override void PreQueueWorkItem() + { + ValidateNotDisposed(); + } + + #endregion + + #region Join, Choice, Pipe, etc. + + /// + /// Executes all actions in parallel. + /// Returns when they all finish. + /// + /// Actions to execute + public void Join(IEnumerable actions) + { + WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; + IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); + foreach (Action action in actions) + { + workItemsGroup.QueueWorkItem(action); + } + workItemsGroup.Start(); + workItemsGroup.WaitForIdle(); + } + + /// + /// Executes all actions in parallel. + /// Returns when they all finish. + /// + /// Actions to execute + public void Join(params Action[] actions) + { + Join((IEnumerable)actions); + } + + private class ChoiceIndex + { + public int _index = -1; + } + + /// + /// Executes all actions in parallel + /// Returns when the first one completes + /// + /// Actions to execute + public int Choice(IEnumerable actions) + { + WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; + IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); + + ManualResetEvent anActionCompleted = new ManualResetEvent(false); + + ChoiceIndex choiceIndex = new ChoiceIndex(); + + int i = 0; + foreach (Action action in actions) + { + Action act = action; + int value = i; + workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); }); + ++i; + } + workItemsGroup.Start(); + anActionCompleted.WaitOne(); + + return choiceIndex._index; + } + + /// + /// Executes all actions in parallel + /// Returns when the first one completes + /// + /// Actions to execute + public int Choice(params Action[] actions) + { + return Choice((IEnumerable)actions); + } + + /// + /// Executes actions in sequence asynchronously. + /// Returns immediately. + /// + /// A state context that passes + /// Actions to execute in the order they should run + public void Pipe(T pipeState, IEnumerable> actions) + { + WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; + IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(1, wigStartInfo); + foreach (Action action in actions) + { + Action act = action; + workItemsGroup.QueueWorkItem(() => act(pipeState)); + } + workItemsGroup.Start(); + workItemsGroup.WaitForIdle(); + } + + /// + /// Executes actions in sequence asynchronously. + /// Returns immediately. + /// + /// + /// Actions to execute in the order they should run + public void Pipe(T pipeState, params Action[] actions) + { + Pipe(pipeState, (IEnumerable>)actions); + } + #endregion + } + #endregion +} diff --git a/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs index 3532cca..0cce19f 100644 --- a/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs +++ b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs @@ -1,89 +1,89 @@ -using System.Collections.Generic; - -namespace Amib.Threading.Internal -{ - internal class SynchronizedDictionary - { - private readonly Dictionary _dictionary; - private readonly object _lock; - - public SynchronizedDictionary() - { - _lock = new object(); - _dictionary = new Dictionary(); - } - - public int Count - { - get { return _dictionary.Count; } - } - - public bool Contains(TKey key) - { - lock (_lock) - { - return _dictionary.ContainsKey(key); - } - } - - public void Remove(TKey key) - { - lock (_lock) - { - _dictionary.Remove(key); - } - } - - public object SyncRoot - { - get { return _lock; } - } - - public TValue this[TKey key] - { - get - { - lock (_lock) - { - return _dictionary[key]; - } - } - set - { - lock (_lock) - { - _dictionary[key] = value; - } - } - } - - public Dictionary.KeyCollection Keys - { - get - { - lock (_lock) - { - return _dictionary.Keys; - } - } - } - - public Dictionary.ValueCollection Values - { - get - { - lock (_lock) - { - return _dictionary.Values; - } - } - } - public void Clear() - { - lock (_lock) - { - _dictionary.Clear(); - } - } - } -} +using System.Collections.Generic; + +namespace Amib.Threading.Internal +{ + internal class SynchronizedDictionary + { + private readonly Dictionary _dictionary; + private readonly object _lock; + + public SynchronizedDictionary() + { + _lock = new object(); + _dictionary = new Dictionary(); + } + + public int Count + { + get { return _dictionary.Count; } + } + + public bool Contains(TKey key) + { + lock (_lock) + { + return _dictionary.ContainsKey(key); + } + } + + public void Remove(TKey key) + { + lock (_lock) + { + _dictionary.Remove(key); + } + } + + public object SyncRoot + { + get { return _lock; } + } + + public TValue this[TKey key] + { + get + { + lock (_lock) + { + return _dictionary[key]; + } + } + set + { + lock (_lock) + { + _dictionary[key] = value; + } + } + } + + public Dictionary.KeyCollection Keys + { + get + { + lock (_lock) + { + return _dictionary.Keys; + } + } + } + + public Dictionary.ValueCollection Values + { + get + { + lock (_lock) + { + return _dictionary.Values; + } + } + } + public void Clear() + { + lock (_lock) + { + _dictionary.Clear(); + } + } + } +} diff --git a/ThirdParty/SmartThreadPool/WIGStartInfo.cs b/ThirdParty/SmartThreadPool/WIGStartInfo.cs index e5ff150..8af195b 100644 --- a/ThirdParty/SmartThreadPool/WIGStartInfo.cs +++ b/ThirdParty/SmartThreadPool/WIGStartInfo.cs @@ -1,171 +1,171 @@ -using System; - -namespace Amib.Threading -{ - /// - /// Summary description for WIGStartInfo. - /// - public class WIGStartInfo - { - private bool _useCallerCallContext; - private bool _useCallerHttpContext; - private bool _disposeOfStateObjects; - private CallToPostExecute _callToPostExecute; - private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; - private bool _startSuspended; - private WorkItemPriority _workItemPriority; - private bool _fillStateWithArgs; - - protected bool _readOnly; - - public WIGStartInfo() - { - _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs; - _workItemPriority = SmartThreadPool.DefaultWorkItemPriority; - _startSuspended = SmartThreadPool.DefaultStartSuspended; - _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; - _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; - _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; - _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; - _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; - } - - public WIGStartInfo(WIGStartInfo wigStartInfo) - { - _useCallerCallContext = wigStartInfo.UseCallerCallContext; - _useCallerHttpContext = wigStartInfo.UseCallerHttpContext; - _disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - _callToPostExecute = wigStartInfo.CallToPostExecute; - _postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; - _workItemPriority = wigStartInfo.WorkItemPriority; - _startSuspended = wigStartInfo.StartSuspended; - _fillStateWithArgs = wigStartInfo.FillStateWithArgs; - } - - protected void ThrowIfReadOnly() - { - if (_readOnly) - { - throw new NotSupportedException("This is a readonly instance and set is not supported"); - } - } - - /// - /// Get/Set if to use the caller's security context - /// - public virtual bool UseCallerCallContext - { - get { return _useCallerCallContext; } - set - { - ThrowIfReadOnly(); - _useCallerCallContext = value; - } - } - - - /// - /// Get/Set if to use the caller's HTTP context - /// - public virtual bool UseCallerHttpContext - { - get { return _useCallerHttpContext; } - set - { - ThrowIfReadOnly(); - _useCallerHttpContext = value; - } - } - - - /// - /// Get/Set if to dispose of the state object of a work item - /// - public virtual bool DisposeOfStateObjects - { - get { return _disposeOfStateObjects; } - set - { - ThrowIfReadOnly(); - _disposeOfStateObjects = value; - } - } - - - /// - /// Get/Set the run the post execute options - /// - public virtual CallToPostExecute CallToPostExecute - { - get { return _callToPostExecute; } - set - { - ThrowIfReadOnly(); - _callToPostExecute = value; - } - } - - - /// - /// Get/Set the default post execute callback - /// - public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback - { - get { return _postExecuteWorkItemCallback; } - set - { - ThrowIfReadOnly(); - _postExecuteWorkItemCallback = value; - } - } - - - /// - /// Get/Set if the work items execution should be suspended until the Start() - /// method is called. - /// - public virtual bool StartSuspended - { - get { return _startSuspended; } - set - { - ThrowIfReadOnly(); - _startSuspended = value; - } - } - - - /// - /// Get/Set the default priority that a work item gets when it is enqueued - /// - public virtual WorkItemPriority WorkItemPriority - { - get { return _workItemPriority; } - set { _workItemPriority = value; } - } - - /// - /// Get/Set the if QueueWorkItem of Action<...>/Func<...> fill the - /// arguments as an object array into the state of the work item. - /// The arguments can be access later by IWorkItemResult.State. - /// - public virtual bool FillStateWithArgs - { - get { return _fillStateWithArgs; } - set - { - ThrowIfReadOnly(); - _fillStateWithArgs = value; - } - } - - /// - /// Get a readonly version of this WIGStartInfo - /// - /// Returns a readonly reference to this WIGStartInfoRO - public WIGStartInfo AsReadOnly() - { - return new WIGStartInfo(this) { _readOnly = true }; - } - } -} +using System; + +namespace Amib.Threading +{ + /// + /// Summary description for WIGStartInfo. + /// + public class WIGStartInfo + { + private bool _useCallerCallContext; + private bool _useCallerHttpContext; + private bool _disposeOfStateObjects; + private CallToPostExecute _callToPostExecute; + private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; + private bool _startSuspended; + private WorkItemPriority _workItemPriority; + private bool _fillStateWithArgs; + + protected bool _readOnly; + + public WIGStartInfo() + { + _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs; + _workItemPriority = SmartThreadPool.DefaultWorkItemPriority; + _startSuspended = SmartThreadPool.DefaultStartSuspended; + _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; + _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; + _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; + _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; + _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; + } + + public WIGStartInfo(WIGStartInfo wigStartInfo) + { + _useCallerCallContext = wigStartInfo.UseCallerCallContext; + _useCallerHttpContext = wigStartInfo.UseCallerHttpContext; + _disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + _callToPostExecute = wigStartInfo.CallToPostExecute; + _postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; + _workItemPriority = wigStartInfo.WorkItemPriority; + _startSuspended = wigStartInfo.StartSuspended; + _fillStateWithArgs = wigStartInfo.FillStateWithArgs; + } + + protected void ThrowIfReadOnly() + { + if (_readOnly) + { + throw new NotSupportedException("This is a readonly instance and set is not supported"); + } + } + + /// + /// Get/Set if to use the caller's security context + /// + public virtual bool UseCallerCallContext + { + get { return _useCallerCallContext; } + set + { + ThrowIfReadOnly(); + _useCallerCallContext = value; + } + } + + + /// + /// Get/Set if to use the caller's HTTP context + /// + public virtual bool UseCallerHttpContext + { + get { return _useCallerHttpContext; } + set + { + ThrowIfReadOnly(); + _useCallerHttpContext = value; + } + } + + + /// + /// Get/Set if to dispose of the state object of a work item + /// + public virtual bool DisposeOfStateObjects + { + get { return _disposeOfStateObjects; } + set + { + ThrowIfReadOnly(); + _disposeOfStateObjects = value; + } + } + + + /// + /// Get/Set the run the post execute options + /// + public virtual CallToPostExecute CallToPostExecute + { + get { return _callToPostExecute; } + set + { + ThrowIfReadOnly(); + _callToPostExecute = value; + } + } + + + /// + /// Get/Set the default post execute callback + /// + public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback + { + get { return _postExecuteWorkItemCallback; } + set + { + ThrowIfReadOnly(); + _postExecuteWorkItemCallback = value; + } + } + + + /// + /// Get/Set if the work items execution should be suspended until the Start() + /// method is called. + /// + public virtual bool StartSuspended + { + get { return _startSuspended; } + set + { + ThrowIfReadOnly(); + _startSuspended = value; + } + } + + + /// + /// Get/Set the default priority that a work item gets when it is enqueued + /// + public virtual WorkItemPriority WorkItemPriority + { + get { return _workItemPriority; } + set { _workItemPriority = value; } + } + + /// + /// Get/Set the if QueueWorkItem of Action<...>/Func<...> fill the + /// arguments as an object array into the state of the work item. + /// The arguments can be access later by IWorkItemResult.State. + /// + public virtual bool FillStateWithArgs + { + get { return _fillStateWithArgs; } + set + { + ThrowIfReadOnly(); + _fillStateWithArgs = value; + } + } + + /// + /// Get a readonly version of this WIGStartInfo + /// + /// Returns a readonly reference to this WIGStartInfoRO + public WIGStartInfo AsReadOnly() + { + return new WIGStartInfo(this) { _readOnly = true }; + } + } +} diff --git a/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs index 5745c15..435a14b 100644 --- a/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs +++ b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs @@ -1,190 +1,190 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace Amib.Threading.Internal -{ - public partial class WorkItem - { - #region WorkItemResult class - - private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult - { - /// - /// A back reference to the work item - /// - private readonly WorkItem _workItem; - - public WorkItemResult(WorkItem workItem) - { - _workItem = workItem; - } - - internal WorkItem GetWorkItem() - { - return _workItem; - } - - #region IWorkItemResult Members - - public bool IsCompleted - { - get - { - return _workItem.IsCompleted; - } - } - - public bool IsCanceled - { - get - { - return _workItem.IsCanceled; - } - } - - public object GetResult() - { - return _workItem.GetResult(Timeout.Infinite, true, null); - } - - public object GetResult(int millisecondsTimeout, bool exitContext) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, null); - } - - public object GetResult(TimeSpan timeout, bool exitContext) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null); - } - - public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); - } - - public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } - - public object GetResult(out Exception e) - { - return _workItem.GetResult(Timeout.Infinite, true, null, out e); - } - - public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e); - } - - public object GetResult(TimeSpan timeout, bool exitContext, out Exception e) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e); - } - - public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); - } - - public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e); - } - - public bool Cancel() - { - return Cancel(false); - } - - public bool Cancel(bool abortExecution) - { - return _workItem.Cancel(abortExecution); - } - - public object State - { - get - { - return _workItem._state; - } - } - - public WorkItemPriority WorkItemPriority - { - get - { - return _workItem._workItemInfo.WorkItemPriority; - } - } - - /// - /// Return the result, same as GetResult() - /// - public object Result - { - get { return GetResult(); } - } - - /// - /// Returns the exception if occured otherwise returns null. - /// This value is valid only after the work item completed, - /// before that it is always null. - /// - public object Exception - { - get { return _workItem._exception; } - } - - #endregion - - #region IInternalWorkItemResult Members - - public event WorkItemStateCallback OnWorkItemStarted - { - add - { - _workItem.OnWorkItemStarted += value; - } - remove - { - _workItem.OnWorkItemStarted -= value; - } - } - - - public event WorkItemStateCallback OnWorkItemCompleted - { - add - { - _workItem.OnWorkItemCompleted += value; - } - remove - { - _workItem.OnWorkItemCompleted -= value; - } - } - - #endregion - - #region IInternalWorkItemResult Members - - public IWorkItemResult GetWorkItemResult() - { - return this; - } - - public IWorkItemResult GetWorkItemResultT() - { - return new WorkItemResultTWrapper(this); - } - - #endregion - } - - #endregion - - } -} +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Amib.Threading.Internal +{ + public partial class WorkItem + { + #region WorkItemResult class + + private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult + { + /// + /// A back reference to the work item + /// + private readonly WorkItem _workItem; + + public WorkItemResult(WorkItem workItem) + { + _workItem = workItem; + } + + internal WorkItem GetWorkItem() + { + return _workItem; + } + + #region IWorkItemResult Members + + public bool IsCompleted + { + get + { + return _workItem.IsCompleted; + } + } + + public bool IsCanceled + { + get + { + return _workItem.IsCanceled; + } + } + + public object GetResult() + { + return _workItem.GetResult(Timeout.Infinite, true, null); + } + + public object GetResult(int millisecondsTimeout, bool exitContext) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, null); + } + + public object GetResult(TimeSpan timeout, bool exitContext) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null); + } + + public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); + } + + public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); + } + + public object GetResult(out Exception e) + { + return _workItem.GetResult(Timeout.Infinite, true, null, out e); + } + + public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e); + } + + public object GetResult(TimeSpan timeout, bool exitContext, out Exception e) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e); + } + + public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); + } + + public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e); + } + + public bool Cancel() + { + return Cancel(false); + } + + public bool Cancel(bool abortExecution) + { + return _workItem.Cancel(abortExecution); + } + + public object State + { + get + { + return _workItem._state; + } + } + + public WorkItemPriority WorkItemPriority + { + get + { + return _workItem._workItemInfo.WorkItemPriority; + } + } + + /// + /// Return the result, same as GetResult() + /// + public object Result + { + get { return GetResult(); } + } + + /// + /// Returns the exception if occured otherwise returns null. + /// This value is valid only after the work item completed, + /// before that it is always null. + /// + public object Exception + { + get { return _workItem._exception; } + } + + #endregion + + #region IInternalWorkItemResult Members + + public event WorkItemStateCallback OnWorkItemStarted + { + add + { + _workItem.OnWorkItemStarted += value; + } + remove + { + _workItem.OnWorkItemStarted -= value; + } + } + + + public event WorkItemStateCallback OnWorkItemCompleted + { + add + { + _workItem.OnWorkItemCompleted += value; + } + remove + { + _workItem.OnWorkItemCompleted -= value; + } + } + + #endregion + + #region IInternalWorkItemResult Members + + public IWorkItemResult GetWorkItemResult() + { + return this; + } + + public IWorkItemResult GetWorkItemResultT() + { + return new WorkItemResultTWrapper(this); + } + + #endregion + } + + #endregion + + } +} diff --git a/ThirdParty/SmartThreadPool/WorkItemFactory.cs b/ThirdParty/SmartThreadPool/WorkItemFactory.cs index 2d6601e..16ccd81 100644 --- a/ThirdParty/SmartThreadPool/WorkItemFactory.cs +++ b/ThirdParty/SmartThreadPool/WorkItemFactory.cs @@ -1,343 +1,343 @@ -using System; - -namespace Amib.Threading.Internal -{ - #region WorkItemFactory class - - public class WorkItemFactory - { - /// - /// Create a new work item - /// - /// The WorkItemsGroup of this workitem - /// Work item group start information - /// A callback to execute - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback) - { - return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null); - } - - /// - /// Create a new work item - /// - /// The WorkItemsGroup of this workitem - /// Work item group start information - /// A callback to execute - /// The priority of the work item - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - WorkItemPriority workItemPriority) - { - return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority); - } - - /// - /// Create a new work item - /// - /// The WorkItemsGroup of this workitem - /// Work item group start information - /// Work item info - /// A callback to execute - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemInfo workItemInfo, - WorkItemCallback callback) - { - return CreateWorkItem( - workItemsGroup, - wigStartInfo, - workItemInfo, - callback, - null); - } - - /// - /// Create a new work item - /// - /// The WorkItemsGroup of this workitem - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state) - { - ValidateCallback(callback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// The work item priority - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - WorkItemPriority workItemPriority) - { - ValidateCallback(callback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = workItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// Work item information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemInfo workItemInfo, - WorkItemCallback callback, - object state) - { - ValidateCallback(callback); - ValidateCallback(workItemInfo.PostExecuteWorkItemCallback); - - WorkItem workItem = new WorkItem( - workItemsGroup, - new WorkItemInfo(workItemInfo), - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback) - { - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// The work item priority - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - WorkItemPriority workItemPriority) - { - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = workItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute) - { - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = callToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// The work item priority - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute, - WorkItemPriority workItemPriority) - { - - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = callToPostExecute; - workItemInfo.WorkItemPriority = workItemPriority; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - private static void ValidateCallback(Delegate callback) - { - if (callback != null && callback.GetInvocationList().Length > 1) - { - throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); - } - } - } - - #endregion -} +using System; + +namespace Amib.Threading.Internal +{ + #region WorkItemFactory class + + public class WorkItemFactory + { + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// A callback to execute + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback) + { + return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null); + } + + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// A callback to execute + /// The priority of the work item + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + WorkItemPriority workItemPriority) + { + return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority); + } + + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// Work item info + /// A callback to execute + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemInfo workItemInfo, + WorkItemCallback callback) + { + return CreateWorkItem( + workItemsGroup, + wigStartInfo, + workItemInfo, + callback, + null); + } + + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state) + { + ValidateCallback(callback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// The work item priority + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + WorkItemPriority workItemPriority) + { + ValidateCallback(callback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = workItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// Work item information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemInfo workItemInfo, + WorkItemCallback callback, + object state) + { + ValidateCallback(callback); + ValidateCallback(workItemInfo.PostExecuteWorkItemCallback); + + WorkItem workItem = new WorkItem( + workItemsGroup, + new WorkItemInfo(workItemInfo), + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback) + { + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// The work item priority + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + WorkItemPriority workItemPriority) + { + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = workItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute) + { + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = callToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// The work item priority + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute, + WorkItemPriority workItemPriority) + { + + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = callToPostExecute; + workItemInfo.WorkItemPriority = workItemPriority; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + private static void ValidateCallback(Delegate callback) + { + if (callback != null && callback.GetInvocationList().Length > 1) + { + throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); + } + } + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/WorkItemInfo.cs b/ThirdParty/SmartThreadPool/WorkItemInfo.cs index 5fbceb8..0d7fc85 100644 --- a/ThirdParty/SmartThreadPool/WorkItemInfo.cs +++ b/ThirdParty/SmartThreadPool/WorkItemInfo.cs @@ -1,69 +1,69 @@ -namespace Amib.Threading -{ - #region WorkItemInfo class - - /// - /// Summary description for WorkItemInfo. - /// - public class WorkItemInfo - { - public WorkItemInfo() - { - UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; - UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; - DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; - CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute; - PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; - WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority; - } - - public WorkItemInfo(WorkItemInfo workItemInfo) - { - UseCallerCallContext = workItemInfo.UseCallerCallContext; - UseCallerHttpContext = workItemInfo.UseCallerHttpContext; - DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects; - CallToPostExecute = workItemInfo.CallToPostExecute; - PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback; - WorkItemPriority = workItemInfo.WorkItemPriority; - Timeout = workItemInfo.Timeout; - } - - /// - /// Get/Set if to use the caller's security context - /// - public bool UseCallerCallContext { get; set; } - - /// - /// Get/Set if to use the caller's HTTP context - /// - public bool UseCallerHttpContext { get; set; } - - /// - /// Get/Set if to dispose of the state object of a work item - /// - public bool DisposeOfStateObjects { get; set; } - - /// - /// Get/Set the run the post execute options - /// - public CallToPostExecute CallToPostExecute { get; set; } - - /// - /// Get/Set the post execute callback - /// - public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; } - - /// - /// Get/Set the work item's priority - /// - public WorkItemPriority WorkItemPriority { get; set; } - - /// - /// Get/Set the work item's timout in milliseconds. - /// This is a passive timout. When the timout expires the work item won't be actively aborted! - /// - public long Timeout { get; set; } - } - - #endregion -} +namespace Amib.Threading +{ + #region WorkItemInfo class + + /// + /// Summary description for WorkItemInfo. + /// + public class WorkItemInfo + { + public WorkItemInfo() + { + UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; + UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; + DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; + CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute; + PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; + WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority; + } + + public WorkItemInfo(WorkItemInfo workItemInfo) + { + UseCallerCallContext = workItemInfo.UseCallerCallContext; + UseCallerHttpContext = workItemInfo.UseCallerHttpContext; + DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects; + CallToPostExecute = workItemInfo.CallToPostExecute; + PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback; + WorkItemPriority = workItemInfo.WorkItemPriority; + Timeout = workItemInfo.Timeout; + } + + /// + /// Get/Set if to use the caller's security context + /// + public bool UseCallerCallContext { get; set; } + + /// + /// Get/Set if to use the caller's HTTP context + /// + public bool UseCallerHttpContext { get; set; } + + /// + /// Get/Set if to dispose of the state object of a work item + /// + public bool DisposeOfStateObjects { get; set; } + + /// + /// Get/Set the run the post execute options + /// + public CallToPostExecute CallToPostExecute { get; set; } + + /// + /// Get/Set the post execute callback + /// + public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; } + + /// + /// Get/Set the work item's priority + /// + public WorkItemPriority WorkItemPriority { get; set; } + + /// + /// Get/Set the work item's timout in milliseconds. + /// This is a passive timout. When the timout expires the work item won't be actively aborted! + /// + public long Timeout { get; set; } + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs index a0bf8b8..d1eff95 100644 --- a/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs +++ b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs @@ -1,128 +1,128 @@ -using System; -using System.Threading; - -namespace Amib.Threading.Internal -{ - #region WorkItemResultTWrapper class - - internal class WorkItemResultTWrapper : IWorkItemResult, IInternalWaitableResult - { - private readonly IWorkItemResult _workItemResult; - - public WorkItemResultTWrapper(IWorkItemResult workItemResult) - { - _workItemResult = workItemResult; - } - - #region IWorkItemResult Members - - public TResult GetResult() - { - return (TResult)_workItemResult.GetResult(); - } - - public TResult GetResult(int millisecondsTimeout, bool exitContext) - { - return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext); - } - - public TResult GetResult(TimeSpan timeout, bool exitContext) - { - return (TResult)_workItemResult.GetResult(timeout, exitContext); - } - - public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) - { - return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); - } - - public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) - { - return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle); - } - - public TResult GetResult(out Exception e) - { - return (TResult)_workItemResult.GetResult(out e); - } - - public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e) - { - return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e); - } - - public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e) - { - return (TResult)_workItemResult.GetResult(timeout, exitContext, out e); - } - - public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) - { - return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); - } - - public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) - { - return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e); - } - - public bool IsCompleted - { - get { return _workItemResult.IsCompleted; } - } - - public bool IsCanceled - { - get { return _workItemResult.IsCanceled; } - } - - public object State - { - get { return _workItemResult.State; } - } - - public bool Cancel() - { - return _workItemResult.Cancel(); - } - - public bool Cancel(bool abortExecution) - { - return _workItemResult.Cancel(abortExecution); - } - - public WorkItemPriority WorkItemPriority - { - get { return _workItemResult.WorkItemPriority; } - } - - public TResult Result - { - get { return (TResult)_workItemResult.Result; } - } - - public object Exception - { - get { return (TResult)_workItemResult.Exception; } - } - - #region IInternalWorkItemResult Members - - public IWorkItemResult GetWorkItemResult() - { - return _workItemResult.GetWorkItemResult(); - } - - public IWorkItemResult GetWorkItemResultT() - { - return (IWorkItemResult)this; - } - - #endregion - - #endregion - } - - #endregion - -} +using System; +using System.Threading; + +namespace Amib.Threading.Internal +{ + #region WorkItemResultTWrapper class + + internal class WorkItemResultTWrapper : IWorkItemResult, IInternalWaitableResult + { + private readonly IWorkItemResult _workItemResult; + + public WorkItemResultTWrapper(IWorkItemResult workItemResult) + { + _workItemResult = workItemResult; + } + + #region IWorkItemResult Members + + public TResult GetResult() + { + return (TResult)_workItemResult.GetResult(); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle); + } + + public TResult GetResult(out Exception e) + { + return (TResult)_workItemResult.GetResult(out e); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext, out e); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e); + } + + public bool IsCompleted + { + get { return _workItemResult.IsCompleted; } + } + + public bool IsCanceled + { + get { return _workItemResult.IsCanceled; } + } + + public object State + { + get { return _workItemResult.State; } + } + + public bool Cancel() + { + return _workItemResult.Cancel(); + } + + public bool Cancel(bool abortExecution) + { + return _workItemResult.Cancel(abortExecution); + } + + public WorkItemPriority WorkItemPriority + { + get { return _workItemResult.WorkItemPriority; } + } + + public TResult Result + { + get { return (TResult)_workItemResult.Result; } + } + + public object Exception + { + get { return (TResult)_workItemResult.Exception; } + } + + #region IInternalWorkItemResult Members + + public IWorkItemResult GetWorkItemResult() + { + return _workItemResult.GetWorkItemResult(); + } + + public IWorkItemResult GetWorkItemResultT() + { + return (IWorkItemResult)this; + } + + #endregion + + #endregion + } + + #endregion + +} diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs index 67dcbdd..d9d34ac 100644 --- a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs +++ b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs @@ -1,361 +1,361 @@ -using System; -using System.Threading; -using System.Runtime.CompilerServices; -using System.Diagnostics; - -namespace Amib.Threading.Internal -{ - - #region WorkItemsGroup class - - /// - /// Summary description for WorkItemsGroup. - /// - public class WorkItemsGroup : WorkItemsGroupBase - { - #region Private members - - private readonly object _lock = new object(); - - /// - /// A reference to the SmartThreadPool instance that created this - /// WorkItemsGroup. - /// - private readonly SmartThreadPool _stp; - - /// - /// The OnIdle event - /// - private event WorkItemsGroupIdleHandler _onIdle; - - /// - /// A flag to indicate if the Work Items Group is now suspended. - /// - private bool _isSuspended; - - /// - /// Defines how many work items of this WorkItemsGroup can run at once. - /// - private int _concurrency; - - /// - /// Priority queue to hold work items before they are passed - /// to the SmartThreadPool. - /// - private readonly PriorityQueue _workItemsQueue; - - /// - /// Indicate how many work items are waiting in the SmartThreadPool - /// queue. - /// This value is used to apply the concurrency. - /// - private int _workItemsInStpQueue; - - /// - /// Indicate how many work items are currently running in the SmartThreadPool. - /// This value is used with the Cancel, to calculate if we can send new - /// work items to the STP. - /// - private int _workItemsExecutingInStp = 0; - - /// - /// WorkItemsGroup start information - /// - private readonly WIGStartInfo _workItemsGroupStartInfo; - - /// - /// Signaled when all of the WorkItemsGroup's work item completed. - /// - //private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); - private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); - - /// - /// A common object for all the work items that this work items group - /// generate so we can mark them to cancel in O(1) - /// - private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); - - #endregion - - #region Construction - - public WorkItemsGroup( - SmartThreadPool stp, - int concurrency, - WIGStartInfo wigStartInfo) - { - if (concurrency <= 0) - { - throw new ArgumentOutOfRangeException( - "concurrency", -#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - concurrency, -#endif - "concurrency must be greater than zero"); - } - _stp = stp; - _concurrency = concurrency; - _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly(); - _workItemsQueue = new PriorityQueue(); - Name = "WorkItemsGroup"; - - // The _workItemsInStpQueue gets the number of currently executing work items, - // because once a work item is executing, it cannot be cancelled. - _workItemsInStpQueue = _workItemsExecutingInStp; - - _isSuspended = _workItemsGroupStartInfo.StartSuspended; - } - - #endregion - - #region WorkItemsGroupBase Overrides - - public override int Concurrency - { - get { return _concurrency; } - set - { - Debug.Assert(value > 0); - - int diff = value - _concurrency; - _concurrency = value; - if (diff > 0) - { - EnqueueToSTPNextNWorkItem(diff); - } - } - } - - public override int WaitingCallbacks - { - get { return _workItemsQueue.Count; } - } - - public override object[] GetStates() - { - lock (_lock) - { - object[] states = new object[_workItemsQueue.Count]; - int i = 0; - foreach (WorkItem workItem in _workItemsQueue) - { - states[i] = workItem.GetWorkItemResult().State; - ++i; - } - return states; - } - } - - /// - /// WorkItemsGroup start information - /// - public override WIGStartInfo WIGStartInfo - { - get { return _workItemsGroupStartInfo; } - } - - /// - /// Start the Work Items Group if it was started suspended - /// - public override void Start() - { - // If the Work Items Group already started then quit - if (!_isSuspended) - { - return; - } - _isSuspended = false; - - EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency)); - } - - public override void Cancel(bool abortExecution) - { - lock (_lock) - { - _canceledWorkItemsGroup.IsCanceled = true; - _workItemsQueue.Clear(); - _workItemsInStpQueue = 0; - _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); - } - - if (abortExecution) - { - _stp.CancelAbortWorkItemsGroup(this); - } - } - - /// - /// Wait for the thread pool to be idle - /// - public override bool WaitForIdle(int millisecondsTimeout) - { - SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this); - return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); - } - - public override event WorkItemsGroupIdleHandler OnIdle - { - add { _onIdle += value; } - remove { _onIdle -= value; } - } - - #endregion - - #region Private methods - - private void RegisterToWorkItemCompletion(IWorkItemResult wir) - { - IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir; - iwir.OnWorkItemStarted += OnWorkItemStartedCallback; - iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback; - } - - public void OnSTPIsStarting() - { - if (_isSuspended) - { - return; - } - - EnqueueToSTPNextNWorkItem(_concurrency); - } - - public void EnqueueToSTPNextNWorkItem(int count) - { - for (int i = 0; i < count; ++i) - { - EnqueueToSTPNextWorkItem(null, false); - } - } - - private object FireOnIdle(object state) - { - FireOnIdleImpl(_onIdle); - return null; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle) - { - if(null == onIdle) - { - return; - } - - Delegate[] delegates = onIdle.GetInvocationList(); - foreach(WorkItemsGroupIdleHandler eh in delegates) - { - try - { - eh(this); - } - catch { } // Suppress exceptions - } - } - - private void OnWorkItemStartedCallback(WorkItem workItem) - { - lock(_lock) - { - ++_workItemsExecutingInStp; - } - } - - private void OnWorkItemCompletedCallback(WorkItem workItem) - { - EnqueueToSTPNextWorkItem(null, true); - } - - internal override void Enqueue(WorkItem workItem) - { - EnqueueToSTPNextWorkItem(workItem); - } - - private void EnqueueToSTPNextWorkItem(WorkItem workItem) - { - EnqueueToSTPNextWorkItem(workItem, false); - } - - private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue) - { - lock(_lock) - { - // Got here from OnWorkItemCompletedCallback() - if (decrementWorkItemsInStpQueue) - { - --_workItemsInStpQueue; - - if(_workItemsInStpQueue < 0) - { - _workItemsInStpQueue = 0; - } - - --_workItemsExecutingInStp; - - if(_workItemsExecutingInStp < 0) - { - _workItemsExecutingInStp = 0; - } - } - - // If the work item is not null then enqueue it - if (null != workItem) - { - workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup; - - RegisterToWorkItemCompletion(workItem.GetWorkItemResult()); - _workItemsQueue.Enqueue(workItem); - //_stp.IncrementWorkItemsCount(); - - if ((1 == _workItemsQueue.Count) && - (0 == _workItemsInStpQueue)) - { - _stp.RegisterWorkItemsGroup(this); - IsIdle = false; - _isIdleWaitHandle.Reset(); - } - } - - // If the work items queue of the group is empty than quit - if (0 == _workItemsQueue.Count) - { - if (0 == _workItemsInStpQueue) - { - _stp.UnregisterWorkItemsGroup(this); - IsIdle = true; - _isIdleWaitHandle.Set(); - if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0) - { - _stp.QueueWorkItem(new WorkItemCallback(FireOnIdle)); - } - } - return; - } - - if (!_isSuspended) - { - if (_workItemsInStpQueue < _concurrency) - { - WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem; - try - { - _stp.Enqueue(nextWorkItem); - } - catch (ObjectDisposedException e) - { - e.GetHashCode(); - // The STP has been shutdown - } - - ++_workItemsInStpQueue; - } - } - } - } - - #endregion - } - - #endregion -} +using System; +using System.Threading; +using System.Runtime.CompilerServices; +using System.Diagnostics; + +namespace Amib.Threading.Internal +{ + + #region WorkItemsGroup class + + /// + /// Summary description for WorkItemsGroup. + /// + public class WorkItemsGroup : WorkItemsGroupBase + { + #region Private members + + private readonly object _lock = new object(); + + /// + /// A reference to the SmartThreadPool instance that created this + /// WorkItemsGroup. + /// + private readonly SmartThreadPool _stp; + + /// + /// The OnIdle event + /// + private event WorkItemsGroupIdleHandler _onIdle; + + /// + /// A flag to indicate if the Work Items Group is now suspended. + /// + private bool _isSuspended; + + /// + /// Defines how many work items of this WorkItemsGroup can run at once. + /// + private int _concurrency; + + /// + /// Priority queue to hold work items before they are passed + /// to the SmartThreadPool. + /// + private readonly PriorityQueue _workItemsQueue; + + /// + /// Indicate how many work items are waiting in the SmartThreadPool + /// queue. + /// This value is used to apply the concurrency. + /// + private int _workItemsInStpQueue; + + /// + /// Indicate how many work items are currently running in the SmartThreadPool. + /// This value is used with the Cancel, to calculate if we can send new + /// work items to the STP. + /// + private int _workItemsExecutingInStp = 0; + + /// + /// WorkItemsGroup start information + /// + private readonly WIGStartInfo _workItemsGroupStartInfo; + + /// + /// Signaled when all of the WorkItemsGroup's work item completed. + /// + //private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); + private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); + + /// + /// A common object for all the work items that this work items group + /// generate so we can mark them to cancel in O(1) + /// + private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); + + #endregion + + #region Construction + + public WorkItemsGroup( + SmartThreadPool stp, + int concurrency, + WIGStartInfo wigStartInfo) + { + if (concurrency <= 0) + { + throw new ArgumentOutOfRangeException( + "concurrency", +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + concurrency, +#endif + "concurrency must be greater than zero"); + } + _stp = stp; + _concurrency = concurrency; + _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly(); + _workItemsQueue = new PriorityQueue(); + Name = "WorkItemsGroup"; + + // The _workItemsInStpQueue gets the number of currently executing work items, + // because once a work item is executing, it cannot be cancelled. + _workItemsInStpQueue = _workItemsExecutingInStp; + + _isSuspended = _workItemsGroupStartInfo.StartSuspended; + } + + #endregion + + #region WorkItemsGroupBase Overrides + + public override int Concurrency + { + get { return _concurrency; } + set + { + Debug.Assert(value > 0); + + int diff = value - _concurrency; + _concurrency = value; + if (diff > 0) + { + EnqueueToSTPNextNWorkItem(diff); + } + } + } + + public override int WaitingCallbacks + { + get { return _workItemsQueue.Count; } + } + + public override object[] GetStates() + { + lock (_lock) + { + object[] states = new object[_workItemsQueue.Count]; + int i = 0; + foreach (WorkItem workItem in _workItemsQueue) + { + states[i] = workItem.GetWorkItemResult().State; + ++i; + } + return states; + } + } + + /// + /// WorkItemsGroup start information + /// + public override WIGStartInfo WIGStartInfo + { + get { return _workItemsGroupStartInfo; } + } + + /// + /// Start the Work Items Group if it was started suspended + /// + public override void Start() + { + // If the Work Items Group already started then quit + if (!_isSuspended) + { + return; + } + _isSuspended = false; + + EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency)); + } + + public override void Cancel(bool abortExecution) + { + lock (_lock) + { + _canceledWorkItemsGroup.IsCanceled = true; + _workItemsQueue.Clear(); + _workItemsInStpQueue = 0; + _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); + } + + if (abortExecution) + { + _stp.CancelAbortWorkItemsGroup(this); + } + } + + /// + /// Wait for the thread pool to be idle + /// + public override bool WaitForIdle(int millisecondsTimeout) + { + SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this); + return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); + } + + public override event WorkItemsGroupIdleHandler OnIdle + { + add { _onIdle += value; } + remove { _onIdle -= value; } + } + + #endregion + + #region Private methods + + private void RegisterToWorkItemCompletion(IWorkItemResult wir) + { + IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir; + iwir.OnWorkItemStarted += OnWorkItemStartedCallback; + iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback; + } + + public void OnSTPIsStarting() + { + if (_isSuspended) + { + return; + } + + EnqueueToSTPNextNWorkItem(_concurrency); + } + + public void EnqueueToSTPNextNWorkItem(int count) + { + for (int i = 0; i < count; ++i) + { + EnqueueToSTPNextWorkItem(null, false); + } + } + + private object FireOnIdle(object state) + { + FireOnIdleImpl(_onIdle); + return null; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle) + { + if(null == onIdle) + { + return; + } + + Delegate[] delegates = onIdle.GetInvocationList(); + foreach(WorkItemsGroupIdleHandler eh in delegates) + { + try + { + eh(this); + } + catch { } // Suppress exceptions + } + } + + private void OnWorkItemStartedCallback(WorkItem workItem) + { + lock(_lock) + { + ++_workItemsExecutingInStp; + } + } + + private void OnWorkItemCompletedCallback(WorkItem workItem) + { + EnqueueToSTPNextWorkItem(null, true); + } + + internal override void Enqueue(WorkItem workItem) + { + EnqueueToSTPNextWorkItem(workItem); + } + + private void EnqueueToSTPNextWorkItem(WorkItem workItem) + { + EnqueueToSTPNextWorkItem(workItem, false); + } + + private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue) + { + lock(_lock) + { + // Got here from OnWorkItemCompletedCallback() + if (decrementWorkItemsInStpQueue) + { + --_workItemsInStpQueue; + + if(_workItemsInStpQueue < 0) + { + _workItemsInStpQueue = 0; + } + + --_workItemsExecutingInStp; + + if(_workItemsExecutingInStp < 0) + { + _workItemsExecutingInStp = 0; + } + } + + // If the work item is not null then enqueue it + if (null != workItem) + { + workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup; + + RegisterToWorkItemCompletion(workItem.GetWorkItemResult()); + _workItemsQueue.Enqueue(workItem); + //_stp.IncrementWorkItemsCount(); + + if ((1 == _workItemsQueue.Count) && + (0 == _workItemsInStpQueue)) + { + _stp.RegisterWorkItemsGroup(this); + IsIdle = false; + _isIdleWaitHandle.Reset(); + } + } + + // If the work items queue of the group is empty than quit + if (0 == _workItemsQueue.Count) + { + if (0 == _workItemsInStpQueue) + { + _stp.UnregisterWorkItemsGroup(this); + IsIdle = true; + _isIdleWaitHandle.Set(); + if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0) + { + _stp.QueueWorkItem(new WorkItemCallback(FireOnIdle)); + } + } + return; + } + + if (!_isSuspended) + { + if (_workItemsInStpQueue < _concurrency) + { + WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem; + try + { + _stp.Enqueue(nextWorkItem); + } + catch (ObjectDisposedException e) + { + e.GetHashCode(); + // The STP has been shutdown + } + + ++_workItemsInStpQueue; + } + } + } + } + + #endregion + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs index 429de12..27fae5e 100644 --- a/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs +++ b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs @@ -1,471 +1,471 @@ -using System; -using System.Threading; - -namespace Amib.Threading.Internal -{ - public abstract class WorkItemsGroupBase : IWorkItemsGroup - { - #region Private Fields - - /// - /// Contains the name of this instance of SmartThreadPool. - /// Can be changed by the user. - /// - private string _name = "WorkItemsGroupBase"; - - public WorkItemsGroupBase() - { - IsIdle = true; - } - - #endregion - - #region IWorkItemsGroup Members - - #region Public Methods - - /// - /// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance - /// - public string Name - { - get { return _name; } - set { _name = value; } - } - - #endregion - - #region Abstract Methods - - public abstract int Concurrency { get; set; } - public abstract int WaitingCallbacks { get; } - public abstract object[] GetStates(); - public abstract WIGStartInfo WIGStartInfo { get; } - public abstract void Start(); - public abstract void Cancel(bool abortExecution); - public abstract bool WaitForIdle(int millisecondsTimeout); - public abstract event WorkItemsGroupIdleHandler OnIdle; - - internal abstract void Enqueue(WorkItem workItem); - internal virtual void PreQueueWorkItem() { } - - #endregion - - #region Common Base Methods - - /// - /// Cancel all the work items. - /// Same as Cancel(false) - /// - public virtual void Cancel() - { - Cancel(false); - } - - /// - /// Wait for the SmartThreadPool/WorkItemsGroup to be idle - /// - public void WaitForIdle() - { - WaitForIdle(Timeout.Infinite); - } - - /// - /// Wait for the SmartThreadPool/WorkItemsGroup to be idle - /// - public bool WaitForIdle(TimeSpan timeout) - { - return WaitForIdle((int)timeout.TotalMilliseconds); - } - - /// - /// IsIdle is true when there are no work items running or queued. - /// - public bool IsIdle { get; protected set; } - - #endregion - - #region QueueWorkItem - - /// - /// Queue a work item - /// - /// A callback to execute - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// The priority of the work item - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// Work item info - /// A callback to execute - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// Work item information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - WorkItemPriority workItemPriority) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute, - WorkItemPriority workItemPriority) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - #endregion - - #region QueueWorkItem(Action<...>) - - public IWorkItemResult QueueWorkItem(Action action) - { - return QueueWorkItem (action, SmartThreadPool.DefaultWorkItemPriority); - } - - public IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority) - { - PreQueueWorkItem (); - WorkItem workItem = WorkItemFactory.CreateWorkItem ( - this, - WIGStartInfo, - delegate - { - action.Invoke (); - return null; - }, priority); - Enqueue (workItem); - return workItem.GetWorkItemResult (); - } - - public IWorkItemResult QueueWorkItem(Action action, T arg) - { - return QueueWorkItem (action, arg, SmartThreadPool.DefaultWorkItemPriority); - } - - public IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority) - { - PreQueueWorkItem (); - WorkItem workItem = WorkItemFactory.CreateWorkItem ( - this, - WIGStartInfo, - state => - { - action.Invoke (arg); - return null; - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority); - Enqueue (workItem); - return workItem.GetWorkItemResult (); - } - - public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2) - { - return QueueWorkItem (action, arg1, arg2, SmartThreadPool.DefaultWorkItemPriority); - } - - public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority) - { - PreQueueWorkItem (); - WorkItem workItem = WorkItemFactory.CreateWorkItem ( - this, - WIGStartInfo, - state => - { - action.Invoke (arg1, arg2); - return null; - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority); - Enqueue (workItem); - return workItem.GetWorkItemResult (); - } - - public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3) - { - return QueueWorkItem (action, arg1, arg2, arg3, SmartThreadPool.DefaultWorkItemPriority); - ; - } - - public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority) - { - PreQueueWorkItem (); - WorkItem workItem = WorkItemFactory.CreateWorkItem ( - this, - WIGStartInfo, - state => - { - action.Invoke (arg1, arg2, arg3); - return null; - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority); - Enqueue (workItem); - return workItem.GetWorkItemResult (); - } - - public IWorkItemResult QueueWorkItem( - Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4) - { - return QueueWorkItem (action, arg1, arg2, arg3, arg4, - SmartThreadPool.DefaultWorkItemPriority); - } - - public IWorkItemResult QueueWorkItem ( - Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority) - { - PreQueueWorkItem (); - WorkItem workItem = WorkItemFactory.CreateWorkItem ( - this, - WIGStartInfo, - state => - { - action.Invoke (arg1, arg2, arg3, arg4); - return null; - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority); - Enqueue (workItem); - return workItem.GetWorkItemResult (); - } - - #endregion - - #region QueueWorkItem(Func<...>) - - public IWorkItemResult QueueWorkItem(Func func) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem( - this, - WIGStartInfo, - state => - { - return func.Invoke(); - }); - Enqueue(workItem); - return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); - } - - public IWorkItemResult QueueWorkItem(Func func, T arg) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem( - this, - WIGStartInfo, - state => - { - return func.Invoke(arg); - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null); - Enqueue(workItem); - return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); - } - - public IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem( - this, - WIGStartInfo, - state => - { - return func.Invoke(arg1, arg2); - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null); - Enqueue(workItem); - return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); - } - - public IWorkItemResult QueueWorkItem( - Func func, T1 arg1, T2 arg2, T3 arg3) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem( - this, - WIGStartInfo, - state => - { - return func.Invoke(arg1, arg2, arg3); - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null); - Enqueue(workItem); - return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); - } - - public IWorkItemResult QueueWorkItem( - Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem( - this, - WIGStartInfo, - state => - { - return func.Invoke(arg1, arg2, arg3, arg4); - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null); - Enqueue(workItem); - return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); - } - - #endregion - - #endregion - } +using System; +using System.Threading; + +namespace Amib.Threading.Internal +{ + public abstract class WorkItemsGroupBase : IWorkItemsGroup + { + #region Private Fields + + /// + /// Contains the name of this instance of SmartThreadPool. + /// Can be changed by the user. + /// + private string _name = "WorkItemsGroupBase"; + + public WorkItemsGroupBase() + { + IsIdle = true; + } + + #endregion + + #region IWorkItemsGroup Members + + #region Public Methods + + /// + /// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance + /// + public string Name + { + get { return _name; } + set { _name = value; } + } + + #endregion + + #region Abstract Methods + + public abstract int Concurrency { get; set; } + public abstract int WaitingCallbacks { get; } + public abstract object[] GetStates(); + public abstract WIGStartInfo WIGStartInfo { get; } + public abstract void Start(); + public abstract void Cancel(bool abortExecution); + public abstract bool WaitForIdle(int millisecondsTimeout); + public abstract event WorkItemsGroupIdleHandler OnIdle; + + internal abstract void Enqueue(WorkItem workItem); + internal virtual void PreQueueWorkItem() { } + + #endregion + + #region Common Base Methods + + /// + /// Cancel all the work items. + /// Same as Cancel(false) + /// + public virtual void Cancel() + { + Cancel(false); + } + + /// + /// Wait for the SmartThreadPool/WorkItemsGroup to be idle + /// + public void WaitForIdle() + { + WaitForIdle(Timeout.Infinite); + } + + /// + /// Wait for the SmartThreadPool/WorkItemsGroup to be idle + /// + public bool WaitForIdle(TimeSpan timeout) + { + return WaitForIdle((int)timeout.TotalMilliseconds); + } + + /// + /// IsIdle is true when there are no work items running or queued. + /// + public bool IsIdle { get; protected set; } + + #endregion + + #region QueueWorkItem + + /// + /// Queue a work item + /// + /// A callback to execute + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback) + { + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// The priority of the work item + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// Work item info + /// A callback to execute + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state) + { + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// The work item priority + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// Work item information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// The work item priority + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// The work item priority + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute, + WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + #endregion + + #region QueueWorkItem(Action<...>) + + public IWorkItemResult QueueWorkItem(Action action) + { + return QueueWorkItem (action, SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + delegate + { + action.Invoke (); + return null; + }, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem(Action action, T arg) + { + return QueueWorkItem (action, arg, SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2) + { + return QueueWorkItem (action, arg1, arg2, SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg1, arg2); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3) + { + return QueueWorkItem (action, arg1, arg2, arg3, SmartThreadPool.DefaultWorkItemPriority); + ; + } + + public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg1, arg2, arg3); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem( + Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + return QueueWorkItem (action, arg1, arg2, arg3, arg4, + SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem ( + Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg1, arg2, arg3, arg4); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + #endregion + + #region QueueWorkItem(Func<...>) + + public IWorkItemResult QueueWorkItem(Func func) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(); + }); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem(Func func, T arg) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg1, arg2); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem( + Func func, T1 arg1, T2 arg2, T3 arg3) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg1, arg2, arg3); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem( + Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg1, arg2, arg3, arg4); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + #endregion + + #endregion + } } \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs index 156a131..e0bc916 100644 --- a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs +++ b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs @@ -1,645 +1,645 @@ -using System; -using System.Collections.Generic; -using System.Threading; - -namespace Amib.Threading.Internal -{ - #region WorkItemsQueue class - - /// - /// WorkItemsQueue class. - /// - public class WorkItemsQueue : IDisposable - { - #region Member variables - - /// - /// Waiters queue (implemented as stack). - /// - private readonly WaiterEntry _headWaiterEntry = new WaiterEntry(); - - /// - /// Waiters count - /// - private int _waitersCount = 0; - - /// - /// Work items queue - /// - private readonly PriorityQueue _workItems = new PriorityQueue(); - - /// - /// Indicate that work items are allowed to be queued - /// - private bool _isWorkItemsQueueActive = true; - - -#if (WINDOWS_PHONE) - private static readonly Dictionary _waiterEntries = new Dictionary(); -#elif (_WINDOWS_CE) - private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot(); -#else - - [ThreadStatic] - private static WaiterEntry _waiterEntry; -#endif - - - /// - /// Each thread in the thread pool keeps its own waiter entry. - /// - private static WaiterEntry CurrentWaiterEntry - { -#if (WINDOWS_PHONE) - get - { - lock (_waiterEntries) - { - WaiterEntry waiterEntry; - if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry)) - { - return waiterEntry; - } - } - return null; - } - set - { - lock (_waiterEntries) - { - _waiterEntries[Thread.CurrentThread.ManagedThreadId] = value; - } - } -#elif (_WINDOWS_CE) - get - { - return Thread.GetData(_waiterEntrySlot) as WaiterEntry; - } - set - { - Thread.SetData(_waiterEntrySlot, value); - } -#else - get - { - return _waiterEntry; - } - set - { - _waiterEntry = value; - } -#endif - } - - /// - /// A flag that indicates if the WorkItemsQueue has been disposed. - /// - private bool _isDisposed = false; - - #endregion - - #region Public properties - - /// - /// Returns the current number of work items in the queue - /// - public int Count - { - get - { - return _workItems.Count; - } - } - - /// - /// Returns the current number of waiters - /// - public int WaitersCount - { - get - { - return _waitersCount; - } - } - - - #endregion - - #region Public methods - - /// - /// Enqueue a work item to the queue. - /// - public bool EnqueueWorkItem(WorkItem workItem) - { - // A work item cannot be null, since null is used in the - // WaitForWorkItem() method to indicate timeout or cancel - if (null == workItem) - { - throw new ArgumentNullException("workItem" , "workItem cannot be null"); - } - - bool enqueue = true; - - // First check if there is a waiter waiting for work item. During - // the check, timed out waiters are ignored. If there is no - // waiter then the work item is queued. - lock(this) - { - ValidateNotDisposed(); - - if (!_isWorkItemsQueueActive) - { - return false; - } - - while(_waitersCount > 0) - { - // Dequeue a waiter. - WaiterEntry waiterEntry = PopWaiter(); - - // Signal the waiter. On success break the loop - if (waiterEntry.Signal(workItem)) - { - enqueue = false; - break; - } - } - - if (enqueue) - { - // Enqueue the work item - _workItems.Enqueue(workItem); - } - } - return true; - } - - - /// - /// Waits for a work item or exits on timeout or cancel - /// - /// Timeout in milliseconds - /// Cancel wait handle - /// Returns true if the resource was granted - public WorkItem DequeueWorkItem( - int millisecondsTimeout, - WaitHandle cancelEvent) - { - // This method cause the caller to wait for a work item. - // If there is at least one waiting work item then the - // method returns immidiately with it. - // - // If there are no waiting work items then the caller - // is queued between other waiters for a work item to arrive. - // - // If a work item didn't come within millisecondsTimeout or - // the user canceled the wait by signaling the cancelEvent - // then the method returns null to indicate that the caller - // didn't get a work item. - - WaiterEntry waiterEntry; - WorkItem workItem = null; - lock (this) - { - ValidateNotDisposed(); - - // If there are waiting work items then take one and return. - if (_workItems.Count > 0) - { - workItem = _workItems.Dequeue() as WorkItem; - return workItem; - } - - // No waiting work items ... - - // Get the waiter entry for the waiters queue - waiterEntry = GetThreadWaiterEntry(); - - // Put the waiter with the other waiters - PushWaiter(waiterEntry); - } - - // Prepare array of wait handle for the WaitHandle.WaitAny() - WaitHandle [] waitHandles = new WaitHandle[] { - waiterEntry.WaitHandle, - cancelEvent }; - - // Wait for an available resource, cancel event, or timeout. - - // During the wait we are supposes to exit the synchronization - // domain. (Placing true as the third argument of the WaitAny()) - // It just doesn't work, I don't know why, so I have two lock(this) - // statments instead of one. - - int index = STPEventWaitHandle.WaitAny( - waitHandles, - millisecondsTimeout, - true); - - lock(this) - { - // success is true if it got a work item. - bool success = (0 == index); - - // The timeout variable is used only for readability. - // (We treat cancel as timeout) - bool timeout = !success; - - // On timeout update the waiterEntry that it is timed out - if (timeout) - { - // The Timeout() fails if the waiter has already been signaled - timeout = waiterEntry.Timeout(); - - // On timeout remove the waiter from the queue. - // Note that the complexity is O(1). - if(timeout) - { - RemoveWaiter(waiterEntry, false); - } - - // Again readability - success = !timeout; - } - - // On success return the work item - if (success) - { - workItem = waiterEntry.WorkItem; - - if (null == workItem) - { - workItem = _workItems.Dequeue() as WorkItem; - } - } - } - // On failure return null. - return workItem; - } - - /// - /// Cleanup the work items queue, hence no more work - /// items are allowed to be queue - /// - private void Cleanup() - { - lock(this) - { - // Deactivate only once - if (!_isWorkItemsQueueActive) - { - return; - } - - // Don't queue more work items - _isWorkItemsQueueActive = false; - - foreach(WorkItem workItem in _workItems) - { - workItem.DisposeOfState(); - } - - // Clear the work items that are already queued - _workItems.Clear(); - - // Note: - // I don't iterate over the queue and dispose of work items's states, - // since if a work item has a state object that is still in use in the - // application then I must not dispose it. - - // Tell the waiters that they were timed out. - // It won't signal them to exit, but to ignore their - // next work item. - while(_waitersCount > 0) - { - WaiterEntry waiterEntry = PopWaiter(); - waiterEntry.Timeout(); - } - } - } - - public object[] GetStates() - { - lock (this) - { - object[] states = new object[_workItems.Count]; - int i = 0; - foreach (WorkItem workItem in _workItems) - { - states[i] = workItem.GetWorkItemResult().State; - ++i; - } - return states; - } - } - - #endregion - - #region Private methods - - /// - /// Returns the WaiterEntry of the current thread - /// - /// - /// In order to avoid creation and destuction of WaiterEntry - /// objects each thread has its own WaiterEntry object. - private static WaiterEntry GetThreadWaiterEntry() - { - if (null == CurrentWaiterEntry) - { - CurrentWaiterEntry = new WaiterEntry(); - } - CurrentWaiterEntry.Reset(); - return CurrentWaiterEntry; - } - - #region Waiters stack methods - - /// - /// Push a new waiter into the waiter's stack - /// - /// A waiter to put in the stack - public void PushWaiter(WaiterEntry newWaiterEntry) - { - // Remove the waiter if it is already in the stack and - // update waiter's count as needed - RemoveWaiter(newWaiterEntry, false); - - // If the stack is empty then newWaiterEntry is the new head of the stack - if (null == _headWaiterEntry._nextWaiterEntry) - { - _headWaiterEntry._nextWaiterEntry = newWaiterEntry; - newWaiterEntry._prevWaiterEntry = _headWaiterEntry; - - } - // If the stack is not empty then put newWaiterEntry as the new head - // of the stack. - else - { - // Save the old first waiter entry - WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; - - // Update the links - _headWaiterEntry._nextWaiterEntry = newWaiterEntry; - newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; - newWaiterEntry._prevWaiterEntry = _headWaiterEntry; - oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; - } - - // Increment the number of waiters - ++_waitersCount; - } - - /// - /// Pop a waiter from the waiter's stack - /// - /// Returns the first waiter in the stack - private WaiterEntry PopWaiter() - { - // Store the current stack head - WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; - - // Store the new stack head - WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; - - // Update the old stack head list links and decrement the number - // waiters. - RemoveWaiter(oldFirstWaiterEntry, true); - - // Update the new stack head - _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry; - if (null != newHeadWaiterEntry) - { - newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry; - } - - // Return the old stack head - return oldFirstWaiterEntry; - } - - /// - /// Remove a waiter from the stack - /// - /// A waiter entry to remove - /// If true the waiter count is always decremented - private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement) - { - // Store the prev entry in the list - WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry; - - // Store the next entry in the list - WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry; - - // A flag to indicate if we need to decrement the waiters count. - // If we got here from PopWaiter then we must decrement. - // If we got here from PushWaiter then we decrement only if - // the waiter was already in the stack. - bool decrementCounter = popDecrement; - - // Null the waiter's entry links - waiterEntry._prevWaiterEntry = null; - waiterEntry._nextWaiterEntry = null; - - // If the waiter entry had a prev link then update it. - // It also means that the waiter is already in the list and we - // need to decrement the waiters count. - if (null != prevWaiterEntry) - { - prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; - decrementCounter = true; - } - - // If the waiter entry had a next link then update it. - // It also means that the waiter is already in the list and we - // need to decrement the waiters count. - if (null != nextWaiterEntry) - { - nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; - decrementCounter = true; - } - - // Decrement the waiters count if needed - if (decrementCounter) - { - --_waitersCount; - } - } - - #endregion - - #endregion - - #region WaiterEntry class - - // A waiter entry in the _waiters queue. - public sealed class WaiterEntry : IDisposable - { - #region Member variables - - /// - /// Event to signal the waiter that it got the work item. - /// - //private AutoResetEvent _waitHandle = new AutoResetEvent(false); - private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent(); - - /// - /// Flag to know if this waiter already quited from the queue - /// because of a timeout. - /// - private bool _isTimedout = false; - - /// - /// Flag to know if the waiter was signaled and got a work item. - /// - private bool _isSignaled = false; - - /// - /// A work item that passed directly to the waiter withou going - /// through the queue - /// - private WorkItem _workItem = null; - - private bool _isDisposed = false; - - // Linked list members - internal WaiterEntry _nextWaiterEntry = null; - internal WaiterEntry _prevWaiterEntry = null; - - #endregion - - #region Construction - - public WaiterEntry() - { - Reset(); - } - - #endregion - - #region Public methods - - public WaitHandle WaitHandle - { - get { return _waitHandle; } - } - - public WorkItem WorkItem - { - get - { - return _workItem; - } - } - - /// - /// Signal the waiter that it got a work item. - /// - /// Return true on success - /// The method fails if Timeout() preceded its call - public bool Signal(WorkItem workItem) - { - lock(this) - { - if (!_isTimedout) - { - _workItem = workItem; - _isSignaled = true; - _waitHandle.Set(); - return true; - } - } - return false; - } - - /// - /// Mark the wait entry that it has been timed out - /// - /// Return true on success - /// The method fails if Signal() preceded its call - public bool Timeout() - { - lock(this) - { - // Time out can happen only if the waiter wasn't marked as - // signaled - if (!_isSignaled) - { - // We don't remove the waiter from the queue, the DequeueWorkItem - // method skips _waiters that were timed out. - _isTimedout = true; - return true; - } - } - return false; - } - - /// - /// Reset the wait entry so it can be used again - /// - public void Reset() - { - _workItem = null; - _isTimedout = false; - _isSignaled = false; - _waitHandle.Reset(); - } - - /// - /// Free resources - /// - public void Close() - { - if (null != _waitHandle) - { - _waitHandle.Close(); - _waitHandle = null; - } - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - lock (this) - { - if (!_isDisposed) - { - Close(); - } - _isDisposed = true; - } - } - - #endregion - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - if (!_isDisposed) - { - Cleanup(); - } - _isDisposed = true; - } - - private void ValidateNotDisposed() - { - if(_isDisposed) - { - throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); - } - } - - #endregion - } - - #endregion -} - +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Amib.Threading.Internal +{ + #region WorkItemsQueue class + + /// + /// WorkItemsQueue class. + /// + public class WorkItemsQueue : IDisposable + { + #region Member variables + + /// + /// Waiters queue (implemented as stack). + /// + private readonly WaiterEntry _headWaiterEntry = new WaiterEntry(); + + /// + /// Waiters count + /// + private int _waitersCount = 0; + + /// + /// Work items queue + /// + private readonly PriorityQueue _workItems = new PriorityQueue(); + + /// + /// Indicate that work items are allowed to be queued + /// + private bool _isWorkItemsQueueActive = true; + + +#if (WINDOWS_PHONE) + private static readonly Dictionary _waiterEntries = new Dictionary(); +#elif (_WINDOWS_CE) + private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot(); +#else + + [ThreadStatic] + private static WaiterEntry _waiterEntry; +#endif + + + /// + /// Each thread in the thread pool keeps its own waiter entry. + /// + private static WaiterEntry CurrentWaiterEntry + { +#if (WINDOWS_PHONE) + get + { + lock (_waiterEntries) + { + WaiterEntry waiterEntry; + if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry)) + { + return waiterEntry; + } + } + return null; + } + set + { + lock (_waiterEntries) + { + _waiterEntries[Thread.CurrentThread.ManagedThreadId] = value; + } + } +#elif (_WINDOWS_CE) + get + { + return Thread.GetData(_waiterEntrySlot) as WaiterEntry; + } + set + { + Thread.SetData(_waiterEntrySlot, value); + } +#else + get + { + return _waiterEntry; + } + set + { + _waiterEntry = value; + } +#endif + } + + /// + /// A flag that indicates if the WorkItemsQueue has been disposed. + /// + private bool _isDisposed = false; + + #endregion + + #region Public properties + + /// + /// Returns the current number of work items in the queue + /// + public int Count + { + get + { + return _workItems.Count; + } + } + + /// + /// Returns the current number of waiters + /// + public int WaitersCount + { + get + { + return _waitersCount; + } + } + + + #endregion + + #region Public methods + + /// + /// Enqueue a work item to the queue. + /// + public bool EnqueueWorkItem(WorkItem workItem) + { + // A work item cannot be null, since null is used in the + // WaitForWorkItem() method to indicate timeout or cancel + if (null == workItem) + { + throw new ArgumentNullException("workItem" , "workItem cannot be null"); + } + + bool enqueue = true; + + // First check if there is a waiter waiting for work item. During + // the check, timed out waiters are ignored. If there is no + // waiter then the work item is queued. + lock(this) + { + ValidateNotDisposed(); + + if (!_isWorkItemsQueueActive) + { + return false; + } + + while(_waitersCount > 0) + { + // Dequeue a waiter. + WaiterEntry waiterEntry = PopWaiter(); + + // Signal the waiter. On success break the loop + if (waiterEntry.Signal(workItem)) + { + enqueue = false; + break; + } + } + + if (enqueue) + { + // Enqueue the work item + _workItems.Enqueue(workItem); + } + } + return true; + } + + + /// + /// Waits for a work item or exits on timeout or cancel + /// + /// Timeout in milliseconds + /// Cancel wait handle + /// Returns true if the resource was granted + public WorkItem DequeueWorkItem( + int millisecondsTimeout, + WaitHandle cancelEvent) + { + // This method cause the caller to wait for a work item. + // If there is at least one waiting work item then the + // method returns immidiately with it. + // + // If there are no waiting work items then the caller + // is queued between other waiters for a work item to arrive. + // + // If a work item didn't come within millisecondsTimeout or + // the user canceled the wait by signaling the cancelEvent + // then the method returns null to indicate that the caller + // didn't get a work item. + + WaiterEntry waiterEntry; + WorkItem workItem = null; + lock (this) + { + ValidateNotDisposed(); + + // If there are waiting work items then take one and return. + if (_workItems.Count > 0) + { + workItem = _workItems.Dequeue() as WorkItem; + return workItem; + } + + // No waiting work items ... + + // Get the waiter entry for the waiters queue + waiterEntry = GetThreadWaiterEntry(); + + // Put the waiter with the other waiters + PushWaiter(waiterEntry); + } + + // Prepare array of wait handle for the WaitHandle.WaitAny() + WaitHandle [] waitHandles = new WaitHandle[] { + waiterEntry.WaitHandle, + cancelEvent }; + + // Wait for an available resource, cancel event, or timeout. + + // During the wait we are supposes to exit the synchronization + // domain. (Placing true as the third argument of the WaitAny()) + // It just doesn't work, I don't know why, so I have two lock(this) + // statments instead of one. + + int index = STPEventWaitHandle.WaitAny( + waitHandles, + millisecondsTimeout, + true); + + lock(this) + { + // success is true if it got a work item. + bool success = (0 == index); + + // The timeout variable is used only for readability. + // (We treat cancel as timeout) + bool timeout = !success; + + // On timeout update the waiterEntry that it is timed out + if (timeout) + { + // The Timeout() fails if the waiter has already been signaled + timeout = waiterEntry.Timeout(); + + // On timeout remove the waiter from the queue. + // Note that the complexity is O(1). + if(timeout) + { + RemoveWaiter(waiterEntry, false); + } + + // Again readability + success = !timeout; + } + + // On success return the work item + if (success) + { + workItem = waiterEntry.WorkItem; + + if (null == workItem) + { + workItem = _workItems.Dequeue() as WorkItem; + } + } + } + // On failure return null. + return workItem; + } + + /// + /// Cleanup the work items queue, hence no more work + /// items are allowed to be queue + /// + private void Cleanup() + { + lock(this) + { + // Deactivate only once + if (!_isWorkItemsQueueActive) + { + return; + } + + // Don't queue more work items + _isWorkItemsQueueActive = false; + + foreach(WorkItem workItem in _workItems) + { + workItem.DisposeOfState(); + } + + // Clear the work items that are already queued + _workItems.Clear(); + + // Note: + // I don't iterate over the queue and dispose of work items's states, + // since if a work item has a state object that is still in use in the + // application then I must not dispose it. + + // Tell the waiters that they were timed out. + // It won't signal them to exit, but to ignore their + // next work item. + while(_waitersCount > 0) + { + WaiterEntry waiterEntry = PopWaiter(); + waiterEntry.Timeout(); + } + } + } + + public object[] GetStates() + { + lock (this) + { + object[] states = new object[_workItems.Count]; + int i = 0; + foreach (WorkItem workItem in _workItems) + { + states[i] = workItem.GetWorkItemResult().State; + ++i; + } + return states; + } + } + + #endregion + + #region Private methods + + /// + /// Returns the WaiterEntry of the current thread + /// + /// + /// In order to avoid creation and destuction of WaiterEntry + /// objects each thread has its own WaiterEntry object. + private static WaiterEntry GetThreadWaiterEntry() + { + if (null == CurrentWaiterEntry) + { + CurrentWaiterEntry = new WaiterEntry(); + } + CurrentWaiterEntry.Reset(); + return CurrentWaiterEntry; + } + + #region Waiters stack methods + + /// + /// Push a new waiter into the waiter's stack + /// + /// A waiter to put in the stack + public void PushWaiter(WaiterEntry newWaiterEntry) + { + // Remove the waiter if it is already in the stack and + // update waiter's count as needed + RemoveWaiter(newWaiterEntry, false); + + // If the stack is empty then newWaiterEntry is the new head of the stack + if (null == _headWaiterEntry._nextWaiterEntry) + { + _headWaiterEntry._nextWaiterEntry = newWaiterEntry; + newWaiterEntry._prevWaiterEntry = _headWaiterEntry; + + } + // If the stack is not empty then put newWaiterEntry as the new head + // of the stack. + else + { + // Save the old first waiter entry + WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; + + // Update the links + _headWaiterEntry._nextWaiterEntry = newWaiterEntry; + newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; + newWaiterEntry._prevWaiterEntry = _headWaiterEntry; + oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; + } + + // Increment the number of waiters + ++_waitersCount; + } + + /// + /// Pop a waiter from the waiter's stack + /// + /// Returns the first waiter in the stack + private WaiterEntry PopWaiter() + { + // Store the current stack head + WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; + + // Store the new stack head + WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; + + // Update the old stack head list links and decrement the number + // waiters. + RemoveWaiter(oldFirstWaiterEntry, true); + + // Update the new stack head + _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry; + if (null != newHeadWaiterEntry) + { + newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry; + } + + // Return the old stack head + return oldFirstWaiterEntry; + } + + /// + /// Remove a waiter from the stack + /// + /// A waiter entry to remove + /// If true the waiter count is always decremented + private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement) + { + // Store the prev entry in the list + WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry; + + // Store the next entry in the list + WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry; + + // A flag to indicate if we need to decrement the waiters count. + // If we got here from PopWaiter then we must decrement. + // If we got here from PushWaiter then we decrement only if + // the waiter was already in the stack. + bool decrementCounter = popDecrement; + + // Null the waiter's entry links + waiterEntry._prevWaiterEntry = null; + waiterEntry._nextWaiterEntry = null; + + // If the waiter entry had a prev link then update it. + // It also means that the waiter is already in the list and we + // need to decrement the waiters count. + if (null != prevWaiterEntry) + { + prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; + decrementCounter = true; + } + + // If the waiter entry had a next link then update it. + // It also means that the waiter is already in the list and we + // need to decrement the waiters count. + if (null != nextWaiterEntry) + { + nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; + decrementCounter = true; + } + + // Decrement the waiters count if needed + if (decrementCounter) + { + --_waitersCount; + } + } + + #endregion + + #endregion + + #region WaiterEntry class + + // A waiter entry in the _waiters queue. + public sealed class WaiterEntry : IDisposable + { + #region Member variables + + /// + /// Event to signal the waiter that it got the work item. + /// + //private AutoResetEvent _waitHandle = new AutoResetEvent(false); + private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent(); + + /// + /// Flag to know if this waiter already quited from the queue + /// because of a timeout. + /// + private bool _isTimedout = false; + + /// + /// Flag to know if the waiter was signaled and got a work item. + /// + private bool _isSignaled = false; + + /// + /// A work item that passed directly to the waiter withou going + /// through the queue + /// + private WorkItem _workItem = null; + + private bool _isDisposed = false; + + // Linked list members + internal WaiterEntry _nextWaiterEntry = null; + internal WaiterEntry _prevWaiterEntry = null; + + #endregion + + #region Construction + + public WaiterEntry() + { + Reset(); + } + + #endregion + + #region Public methods + + public WaitHandle WaitHandle + { + get { return _waitHandle; } + } + + public WorkItem WorkItem + { + get + { + return _workItem; + } + } + + /// + /// Signal the waiter that it got a work item. + /// + /// Return true on success + /// The method fails if Timeout() preceded its call + public bool Signal(WorkItem workItem) + { + lock(this) + { + if (!_isTimedout) + { + _workItem = workItem; + _isSignaled = true; + _waitHandle.Set(); + return true; + } + } + return false; + } + + /// + /// Mark the wait entry that it has been timed out + /// + /// Return true on success + /// The method fails if Signal() preceded its call + public bool Timeout() + { + lock(this) + { + // Time out can happen only if the waiter wasn't marked as + // signaled + if (!_isSignaled) + { + // We don't remove the waiter from the queue, the DequeueWorkItem + // method skips _waiters that were timed out. + _isTimedout = true; + return true; + } + } + return false; + } + + /// + /// Reset the wait entry so it can be used again + /// + public void Reset() + { + _workItem = null; + _isTimedout = false; + _isSignaled = false; + _waitHandle.Reset(); + } + + /// + /// Free resources + /// + public void Close() + { + if (null != _waitHandle) + { + _waitHandle.Close(); + _waitHandle = null; + } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + lock (this) + { + if (!_isDisposed) + { + Close(); + } + _isDisposed = true; + } + } + + #endregion + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!_isDisposed) + { + Cleanup(); + } + _isDisposed = true; + } + + private void ValidateNotDisposed() + { + if(_isDisposed) + { + throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); + } + } + + #endregion + } + + #endregion +} + -- cgit v1.1