Update SmartThreadPool to latest version 2.2.3 with a major and minor change.

SmartThreadPool code comes from http://www.codeproject.com/Articles/7933/Smart-Thread-Pool
This version implements thread abort (via WorkItem.Cancel(true)), threadpool naming, max thread stack, etc. so we no longer need to manually patch those.
However, two changes have been made to stock 2.2.3.
Major change: WorkItem.Cancel(bool abortExecution) in our version does not succeed if the work item was in progress and thread abort was not specified.
This is to match previous behaviour where we handle co-operative termination via another mechanism rather than checking WorkItem.IsCanceled.
Minor change: Did not add STP's StopWatch implementation as this is only used WinCE and Silverlight and causes a build clash with System.Diagnostics.StopWatch
The reason for updating is to see if this improves http://opensimulator.org/mantis/view.php?id=6557 and http://opensimulator.org/mantis/view.php?id=6586
user_profiles
Justin Clark-Casey (justincc) 2013-05-01 19:01:43 +01:00
parent ac135c649c
commit 206fb306a7
31 changed files with 6690 additions and 4804 deletions

View File

@ -1840,7 +1840,7 @@ namespace OpenSim.Framework
case FireAndForgetMethod.SmartThreadPool: case FireAndForgetMethod.SmartThreadPool:
if (m_ThreadPool == null) if (m_ThreadPool == null)
InitThreadPool(15); InitThreadPool(15);
m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
break; break;
case FireAndForgetMethod.Thread: case FireAndForgetMethod.Thread:
Thread thread = new Thread(delegate(object o) { realCallback(o); }); Thread thread = new Thread(delegate(object o) { realCallback(o); });
@ -1910,15 +1910,15 @@ namespace OpenSim.Framework
return sb.ToString(); return sb.ToString();
} }
private static object SmartThreadPoolCallback(object o) // private static object SmartThreadPoolCallback(object o)
{ // {
object[] array = (object[])o; // object[] array = (object[])o;
WaitCallback callback = (WaitCallback)array[0]; // WaitCallback callback = (WaitCallback)array[0];
object obj = array[1]; // object obj = array[1];
//
callback(obj); // callback(obj);
return null; // return null;
} // }
#endregion FireAndForget Threading Pattern #endregion FireAndForget Threading Pattern

View File

@ -51,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
public interface IScriptWorkItem public interface IScriptWorkItem
{ {
bool Cancel(); bool Cancel();
void Abort(); bool Abort();
/// <summary> /// <summary>
/// Wait for the work item to complete. /// Wait for the work item to complete.

View File

@ -564,9 +564,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
public bool Stop(int timeout) public bool Stop(int timeout)
{ {
// m_log.DebugFormat( if (DebugLevel >= 1)
// "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", m_log.DebugFormat(
// ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}",
ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks);
IScriptWorkItem workItem; IScriptWorkItem workItem;
@ -627,6 +628,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
} }
} }
Console.WriteLine("Here9");
lock (EventQueue) lock (EventQueue)
{ {
workItem = m_CurrentWorkItem; workItem = m_CurrentWorkItem;

View File

@ -483,7 +483,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
/// <param name="instance"></param> /// <param name="instance"></param>
/// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param> /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
private void HandleScriptsAction<TKey>( private void HandleScriptsAction<TKey>(
string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector) string[] cmdparams, Action<IScriptInstance> action, System.Func<IScriptInstance, TKey> keySelector)
{ {
if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
return; return;
@ -1517,7 +1517,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
startInfo.MaxWorkerThreads = maxThreads; startInfo.MaxWorkerThreads = maxThreads;
startInfo.MinWorkerThreads = minThreads; startInfo.MinWorkerThreads = minThreads;
startInfo.ThreadPriority = threadPriority;; startInfo.ThreadPriority = threadPriority;;
startInfo.StackSize = stackSize; startInfo.MaxStackSize = stackSize;
startInfo.StartSuspended = true; startInfo.StartSuspended = true;
m_ThreadPool = new SmartThreadPool(startInfo); m_ThreadPool = new SmartThreadPool(startInfo);

View File

@ -52,16 +52,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine
return wr.Cancel(); return wr.Cancel();
} }
public void Abort() public bool Abort()
{ {
wr.Abort(); return wr.Cancel(true);
} }
public bool Wait(int t) public bool Wait(int t)
{ {
// We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the
// TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an
// int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8 // int (32-bit) we can end up with bad values. This occurs on Windows though curiously not on Mono 2.10.8
// (or very likely other versions of Mono at least up until 3.0.3). // (or very likely other versions of Mono at least up until 3.0.3).
return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false);
} }

View File

@ -1,61 +0,0 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: CLSCompliant(true)]
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("0.7.6.*")]
//
// In order to sign your assembly you must specify a key to use. Refer to the
// Microsoft .NET Framework documentation for more information on assembly signing.
//
// Use the attributes below to control which key is used for signing.
//
// Notes:
// (*) If no key is specified, the assembly is not signed.
// (*) KeyName refers to a key that has been installed in the Crypto Service
// Provider (CSP) on your machine. KeyFile refers to a file which contains
// a key.
// (*) If the KeyFile and the KeyName values are both specified, the
// following processing occurs:
// (1) If the KeyName can be found in the CSP, that key is used.
// (2) If the KeyName does not exist and the KeyFile does exist, the key
// in the KeyFile is installed into the CSP and used.
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
// When specifying the KeyFile, the location of the KeyFile should be
// relative to the project output directory which is
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
// located in the project directory, you would specify the AssemblyKeyFile
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
// documentation for more information on this.
//
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]

View File

@ -1,223 +1,138 @@
using System;
using System.Diagnostics; #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
using System.Threading;
using System.Reflection; using System;
using System.Web; using System.Diagnostics;
using System.Runtime.Remoting.Messaging; using System.Threading;
using System.Reflection;
using System.Web;
namespace Amib.Threading using System.Runtime.Remoting.Messaging;
{
#region CallerThreadContext class
namespace Amib.Threading.Internal
/// <summary> {
/// This class stores the caller call context in order to restore #region CallerThreadContext class
/// it when the work item is executed in the thread pool environment.
/// </summary> /// <summary>
internal class CallerThreadContext /// This class stores the caller call context in order to restore
{ /// it when the work item is executed in the thread pool environment.
#region Prepare reflection information /// </summary>
internal class CallerThreadContext
// Cached type information. {
private static MethodInfo getLogicalCallContextMethodInfo = #region Prepare reflection information
typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
// Cached type information.
private static MethodInfo setLogicalCallContextMethodInfo = private static readonly MethodInfo getLogicalCallContextMethodInfo =
typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
private static string HttpContextSlotName = GetHttpContextSlotName(); private static readonly MethodInfo setLogicalCallContextMethodInfo =
typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
private static string GetHttpContextSlotName()
{ private static string HttpContextSlotName = GetHttpContextSlotName();
FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
private static string GetHttpContextSlotName()
if( fi != null ) {
return (string)fi.GetValue(null); FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
else // Use the default "HttpContext" slot name
return "HttpContext"; if (fi != null)
} {
return (string) fi.GetValue(null);
#endregion }
#region Private fields return "HttpContext";
}
private HttpContext _httpContext = null;
private LogicalCallContext _callContext = null; #endregion
#endregion #region Private fields
/// <summary> private HttpContext _httpContext;
/// Constructor private LogicalCallContext _callContext;
/// </summary>
private CallerThreadContext() #endregion
{
} /// <summary>
/// Constructor
public bool CapturedCallContext /// </summary>
{ private CallerThreadContext()
get {
{ }
return (null != _callContext);
} public bool CapturedCallContext
} {
get
public bool CapturedHttpContext {
{ return (null != _callContext);
get }
{ }
return (null != _httpContext);
} public bool CapturedHttpContext
} {
get
/// <summary> {
/// Captures the current thread context return (null != _httpContext);
/// </summary> }
/// <returns></returns> }
public static CallerThreadContext Capture(
bool captureCallContext, /// <summary>
bool captureHttpContext) /// Captures the current thread context
{ /// </summary>
Debug.Assert(captureCallContext || captureHttpContext); /// <returns></returns>
public static CallerThreadContext Capture(
CallerThreadContext callerThreadContext = new CallerThreadContext(); bool captureCallContext,
bool captureHttpContext)
// TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture() {
// Capture Call Context Debug.Assert(captureCallContext || captureHttpContext);
if(captureCallContext && (getLogicalCallContextMethodInfo != null))
{ CallerThreadContext callerThreadContext = new CallerThreadContext();
callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
if (callerThreadContext._callContext != null) // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
{ // Capture Call Context
callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone(); if(captureCallContext && (getLogicalCallContextMethodInfo != null))
} {
} callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
if (callerThreadContext._callContext != null)
// Capture httpContext {
if (captureHttpContext && (null != HttpContext.Current)) callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
{ }
callerThreadContext._httpContext = HttpContext.Current; }
}
// Capture httpContext
return callerThreadContext; if (captureHttpContext && (null != HttpContext.Current))
} {
callerThreadContext._httpContext = HttpContext.Current;
/// <summary> }
/// Applies the thread context stored earlier
/// </summary> return callerThreadContext;
/// <param name="callerThreadContext"></param> }
public static void Apply(CallerThreadContext callerThreadContext)
{ /// <summary>
if (null == callerThreadContext) /// Applies the thread context stored earlier
{ /// </summary>
throw new ArgumentNullException("callerThreadContext"); /// <param name="callerThreadContext"></param>
} public static void Apply(CallerThreadContext callerThreadContext)
{
// Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run() if (null == callerThreadContext)
// Restore call context {
if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null)) throw new ArgumentNullException("callerThreadContext");
{ }
setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
} // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
// Restore call context
// Restore HttpContext if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
if (callerThreadContext._httpContext != null) {
{ setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext); }
}
} // Restore HttpContext
} if (callerThreadContext._httpContext != null)
{
#endregion HttpContext.Current = callerThreadContext._httpContext;
//CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
} }
}
}
/*
// Ami Bar #endregion
// amibar@gmail.com }
#endif
using System;
using System.Threading;
using System.Globalization;
using System.Security.Principal;
using System.Reflection;
using System.Runtime.Remoting.Contexts;
namespace Amib.Threading.Internal
{
#region CallerThreadContext class
/// <summary>
/// This class stores the caller thread context in order to restore
/// it when the work item is executed in the context of the thread
/// from the pool.
/// Note that we can't store the thread's CompressedStack, because
/// it throws a security exception
/// </summary>
public class CallerThreadContext
{
private CultureInfo _culture = null;
private CultureInfo _cultureUI = null;
private IPrincipal _principal;
private System.Runtime.Remoting.Contexts.Context _context;
private static FieldInfo _fieldInfo = GetFieldInfo();
private static FieldInfo GetFieldInfo()
{
Type threadType = typeof(Thread);
return threadType.GetField(
"m_Context",
BindingFlags.Instance | BindingFlags.NonPublic);
}
/// <summary>
/// Constructor
/// </summary>
private CallerThreadContext()
{
}
/// <summary>
/// Captures the current thread context
/// </summary>
/// <returns></returns>
public static CallerThreadContext Capture()
{
CallerThreadContext callerThreadContext = new CallerThreadContext();
Thread thread = Thread.CurrentThread;
callerThreadContext._culture = thread.CurrentCulture;
callerThreadContext._cultureUI = thread.CurrentUICulture;
callerThreadContext._principal = Thread.CurrentPrincipal;
callerThreadContext._context = Thread.CurrentContext;
return callerThreadContext;
}
/// <summary>
/// Applies the thread context stored earlier
/// </summary>
/// <param name="callerThreadContext"></param>
public static void Apply(CallerThreadContext callerThreadContext)
{
Thread thread = Thread.CurrentThread;
thread.CurrentCulture = callerThreadContext._culture;
thread.CurrentUICulture = callerThreadContext._cultureUI;
Thread.CurrentPrincipal = callerThreadContext._principal;
// Uncomment the following block to enable the Thread.CurrentThread
/*
if (null != _fieldInfo)
{
_fieldInfo.SetValue(
Thread.CurrentThread,
callerThreadContext._context);
}
* /
}
}
#endregion
}
*/

View File

@ -0,0 +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; }
}
}

View File

@ -0,0 +1,104 @@
#if (_WINDOWS_CE)
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace Amib.Threading.Internal
{
/// <summary>
/// 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!
/// </summary>
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

View File

@ -0,0 +1,82 @@
using System.Threading;
#if (_WINDOWS_CE)
using System;
using System.Runtime.InteropServices;
#endif
namespace Amib.Threading.Internal
{
/// <summary>
/// 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.
/// </summary>
public static class EventWaitHandleFactory
{
/// <summary>
/// Create a new AutoResetEvent object
/// </summary>
/// <returns>Return a new AutoResetEvent object</returns>
public static AutoResetEvent CreateAutoResetEvent()
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
#if (_WINDOWS_CE)
ReplaceEventHandle(waitHandle, false, false);
#endif
return waitHandle;
}
/// <summary>
/// Create a new ManualResetEvent object
/// </summary>
/// <returns>Return a new ManualResetEvent object</returns>
public static ManualResetEvent CreateManualResetEvent(bool initialState)
{
ManualResetEvent waitHandle = new ManualResetEvent(initialState);
#if (_WINDOWS_CE)
ReplaceEventHandle(waitHandle, true, initialState);
#endif
return waitHandle;
}
#if (_WINDOWS_CE)
/// <summary>
/// Replace the event handle
/// </summary>
/// <param name="waitHandle">The WaitHandle object which its handle needs to be replaced.</param>
/// <param name="manualReset">Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false)</param>
/// <param name="initialState">The initial state of the event</param>
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
}
}

View File

@ -1,81 +1,111 @@
// Ami Bar using System;
// amibar@gmail.com #if !(_WINDOWS_CE)
using System.Runtime.Serialization;
using System; #endif
using System.Runtime.Serialization;
namespace Amib.Threading
namespace Amib.Threading {
{ #region Exceptions
#region Exceptions
/// <summary>
/// <summary> /// Represents an exception in case IWorkItemResult.GetResult has been canceled
/// Represents an exception in case IWorkItemResult.GetResult has been canceled /// </summary>
/// </summary> public sealed partial class WorkItemCancelException : Exception
[Serializable] {
public sealed class WorkItemCancelException : ApplicationException public WorkItemCancelException()
{ {
public WorkItemCancelException() : base() }
{
} public WorkItemCancelException(string message)
: base(message)
public WorkItemCancelException(string message) : base(message) {
{ }
}
public WorkItemCancelException(string message, Exception e)
public WorkItemCancelException(string message, Exception e) : base(message, e) : base(message, e)
{ {
} }
}
public WorkItemCancelException(SerializationInfo si, StreamingContext sc) : base(si, sc)
{ /// <summary>
} /// Represents an exception in case IWorkItemResult.GetResult has been timed out
} /// </summary>
public sealed partial class WorkItemTimeoutException : Exception
/// <summary> {
/// Represents an exception in case IWorkItemResult.GetResult has been timed out public WorkItemTimeoutException()
/// </summary> {
[Serializable] }
public sealed class WorkItemTimeoutException : ApplicationException
{ public WorkItemTimeoutException(string message)
public WorkItemTimeoutException() : base() : base(message)
{ {
} }
public WorkItemTimeoutException(string message) : base(message) public WorkItemTimeoutException(string message, Exception e)
{ : base(message, e)
} {
}
public WorkItemTimeoutException(string message, Exception e) : base(message, e) }
{
} /// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) : base(si, sc) /// </summary>
{ public sealed partial class WorkItemResultException : Exception
} {
} public WorkItemResultException()
{
/// <summary> }
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
/// </summary> public WorkItemResultException(string message)
[Serializable] : base(message)
public sealed class WorkItemResultException : ApplicationException {
{ }
public WorkItemResultException() : base()
{ public WorkItemResultException(string message, Exception e)
} : base(message, e)
{
public WorkItemResultException(string message) : base(message) }
{ }
}
public WorkItemResultException(string message, Exception e) : base(message, e) #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
{ /// <summary>
} /// Represents an exception in case IWorkItemResult.GetResult has been canceled
/// </summary>
public WorkItemResultException(SerializationInfo si, StreamingContext sc) : base(si, sc) [Serializable]
{ public sealed partial class WorkItemCancelException
} {
} public WorkItemCancelException(SerializationInfo si, StreamingContext sc)
: base(si, sc)
#endregion {
} }
}
/// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
/// </summary>
[Serializable]
public sealed partial class WorkItemTimeoutException
{
public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc)
: base(si, sc)
{
}
}
/// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
/// </summary>
[Serializable]
public sealed partial class WorkItemResultException
{
public WorkItemResultException(SerializationInfo si, StreamingContext sc)
: base(si, sc)
{
}
}
#endif
#endregion
}

View File

@ -1,271 +1,628 @@
// Ami Bar using System;
// amibar@gmail.com using System.Threading;
using System; namespace Amib.Threading
using System.Threading; {
#region Delegates
namespace Amib.Threading
{ /// <summary>
#region Delegates /// A delegate that represents the method to run as the work item
/// </summary>
/// <summary> /// <param name="state">A state object for the method to run</param>
/// A delegate that represents the method to run as the work item public delegate object WorkItemCallback(object state);
/// </summary>
/// <param name="state">A state object for the method to run</param> /// <summary>
public delegate object WorkItemCallback(object state); /// A delegate to call after the WorkItemCallback completed
/// </summary>
/// <summary> /// <param name="wir">The work item result object</param>
/// A delegate to call after the WorkItemCallback completed public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
/// </summary>
/// <param name="wir">The work item result object</param> /// <summary>
public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); /// A delegate to call after the WorkItemCallback completed
/// </summary>
/// <summary> /// <param name="wir">The work item result object</param>
/// A delegate to call when a WorkItemsGroup becomes idle public delegate void PostExecuteWorkItemCallback<TResult>(IWorkItemResult<TResult> wir);
/// </summary>
/// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param> /// <summary>
public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup); /// A delegate to call when a WorkItemsGroup becomes idle
/// </summary>
#endregion /// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param>
public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
#region WorkItem Priority
/// <summary>
public enum WorkItemPriority /// A delegate to call after a thread is created, but before
{ /// it's first use.
Lowest, /// </summary>
BelowNormal, public delegate void ThreadInitializationHandler();
Normal,
AboveNormal, /// <summary>
Highest, /// A delegate to call when a thread is about to exit, after
} /// it is no longer belong to the pool.
/// </summary>
#endregion public delegate void ThreadTerminationHandler();
#region IHasWorkItemPriority interface #endregion
public interface IHasWorkItemPriority #region WorkItem Priority
{
WorkItemPriority WorkItemPriority { get; } /// <summary>
} /// Defines the availeable priorities of a work item.
/// The higher the priority a work item has, the sooner
#endregion /// it will be executed.
/// </summary>
#region IWorkItemsGroup interface public enum WorkItemPriority
{
/// <summary> Lowest,
/// IWorkItemsGroup interface BelowNormal,
/// </summary> Normal,
public interface IWorkItemsGroup AboveNormal,
{ Highest,
/// <summary> }
/// Get/Set the name of the WorkItemsGroup
/// </summary> #endregion
string Name { get; set; }
#region IWorkItemsGroup interface
IWorkItemResult QueueWorkItem(WorkItemCallback callback);
IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); /// <summary>
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); /// IWorkItemsGroup interface
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); /// Created by SmartThreadPool.CreateWorkItemsGroup()
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); /// </summary>
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); public interface IWorkItemsGroup
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); {
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); /// <summary>
/// Get/Set the name of the WorkItemsGroup
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); /// </summary>
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); string Name { get; set; }
void WaitForIdle(); /// <summary>
bool WaitForIdle(TimeSpan timeout); /// Get/Set the maximum number of workitem that execute cocurrency on the thread pool
bool WaitForIdle(int millisecondsTimeout); /// </summary>
int Concurrency { get; set; }
int WaitingCallbacks { get; }
event WorkItemsGroupIdleHandler OnIdle; /// <summary>
/// Get the number of work items waiting in the queue.
void Cancel(); /// </summary>
void Start(); int WaitingCallbacks { get; }
}
/// <summary>
#endregion /// Get an array with all the state objects of the currently running items.
/// The array represents a snap shot and impact performance.
#region CallToPostExecute enumerator /// </summary>
object[] GetStates();
[Flags]
public enum CallToPostExecute /// <summary>
{ /// Get the WorkItemsGroup start information
Never = 0x00, /// </summary>
WhenWorkItemCanceled = 0x01, WIGStartInfo WIGStartInfo { get; }
WhenWorkItemNotCanceled = 0x02,
Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled, /// <summary>
} /// Starts to execute work items
/// </summary>
#endregion void Start();
#region IWorkItemResult interface /// <summary>
/// Cancel all the work items.
/// <summary> /// Same as Cancel(false)
/// IWorkItemResult interface /// </summary>
/// </summary> void Cancel();
public interface IWorkItemResult
{ /// <summary>
/// <summary> /// Cancel all work items using thread abortion
/// Get the result of the work item. /// </summary>
/// If the work item didn't run yet then the caller waits. /// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param>
/// </summary> void Cancel(bool abortExecution);
/// <returns>The result of the work item</returns>
object GetResult(); /// <summary>
/// Wait for all work item to complete.
/// <summary> /// </summary>
/// Get the result of the work item. void WaitForIdle();
/// If the work item didn't run yet then the caller waits until timeout.
/// </summary> /// <summary>
/// <returns>The result of the work item</returns> /// Wait for all work item to complete, until timeout expired
/// On timeout throws WorkItemTimeoutException /// </summary>
object GetResult( /// <param name="timeout">How long to wait for the work items to complete</param>
int millisecondsTimeout, /// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
bool exitContext); bool WaitForIdle(TimeSpan timeout);
/// <summary> /// <summary>
/// Get the result of the work item. /// Wait for all work item to complete, until timeout expired
/// If the work item didn't run yet then the caller waits until timeout. /// </summary>
/// </summary> /// <param name="millisecondsTimeout">How long to wait for the work items to complete in milliseconds</param>
/// <returns>The result of the work item</returns> /// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
/// On timeout throws WorkItemTimeoutException bool WaitForIdle(int millisecondsTimeout);
object GetResult(
TimeSpan timeout, /// <summary>
bool exitContext); /// IsIdle is true when there are no work items running or queued.
/// </summary>
void Abort(); bool IsIdle { get; }
/// <summary> /// <summary>
/// Get the result of the work item. /// This event is fired when all work items are completed.
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. /// (When IsIdle changes to true)
/// </summary> /// This event only work on WorkItemsGroup. On SmartThreadPool
/// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param> /// it throws the NotImplementedException.
/// <param name="exitContext"> /// </summary>
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. event WorkItemsGroupIdleHandler OnIdle;
/// </param>
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param> #region QueueWorkItem
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException /// <summary>
/// On cancel throws WorkItemCancelException /// Queue a work item
object GetResult( /// </summary>
int millisecondsTimeout, /// <param name="callback">A callback to execute</param>
bool exitContext, /// <returns>Returns a work item result</returns>
WaitHandle cancelWaitHandle); IWorkItemResult QueueWorkItem(WorkItemCallback callback);
/// <summary> /// <summary>
/// Get the result of the work item. /// Queue a work item
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. /// </summary>
/// </summary> /// <param name="callback">A callback to execute</param>
/// <returns>The result of the work item</returns> /// <param name="workItemPriority">The priority of the work item</param>
/// On timeout throws WorkItemTimeoutException /// <returns>Returns a work item result</returns>
/// On cancel throws WorkItemCancelException IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
object GetResult(
TimeSpan timeout, /// <summary>
bool exitContext, /// Queue a work item
WaitHandle cancelWaitHandle); /// </summary>
/// <param name="callback">A callback to execute</param>
/// <summary> /// <param name="state">
/// Get the result of the work item. /// The context object of the work item. Used for passing arguments to the work item.
/// If the work item didn't run yet then the caller waits. /// </param>
/// </summary> /// <returns>Returns a work item result</returns>
/// <param name="e">Filled with the exception if one was thrown</param> IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
/// <returns>The result of the work item</returns>
object GetResult(out Exception e); /// <summary>
/// Queue a work item
/// <summary> /// </summary>
/// Get the result of the work item. /// <param name="callback">A callback to execute</param>
/// If the work item didn't run yet then the caller waits until timeout. /// <param name="state">
/// </summary> /// The context object of the work item. Used for passing arguments to the work item.
/// <param name="e">Filled with the exception if one was thrown</param> /// </param>
/// <returns>The result of the work item</returns> /// <param name="workItemPriority">The work item priority</param>
/// On timeout throws WorkItemTimeoutException /// <returns>Returns a work item result</returns>
object GetResult( IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
int millisecondsTimeout,
bool exitContext, /// <summary>
out Exception e); /// Queue a work item
/// </summary>
/// <summary> /// <param name="callback">A callback to execute</param>
/// Get the result of the work item. /// <param name="state">
/// If the work item didn't run yet then the caller waits until timeout. /// The context object of the work item. Used for passing arguments to the work item.
/// </summary> /// </param>
/// <param name="e">Filled with the exception if one was thrown</param> /// <param name="postExecuteWorkItemCallback">
/// <returns>The result of the work item</returns> /// A delegate to call after the callback completion
/// On timeout throws WorkItemTimeoutException /// </param>
object GetResult( /// <returns>Returns a work item result</returns>
TimeSpan timeout, IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
bool exitContext,
out Exception e); /// <summary>
/// Queue a work item
/// <summary> /// </summary>
/// Get the result of the work item. /// <param name="callback">A callback to execute</param>
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. /// <param name="state">
/// </summary> /// The context object of the work item. Used for passing arguments to the work item.
/// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param> /// </param>
/// <param name="exitContext"> /// <param name="postExecuteWorkItemCallback">
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. /// A delegate to call after the callback completion
/// </param> /// </param>
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param> /// <param name="workItemPriority">The work item priority</param>
/// <param name="e">Filled with the exception if one was thrown</param> /// <returns>Returns a work item result</returns>
/// <returns>The result of the work item</returns> IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException /// <summary>
object GetResult( /// Queue a work item
int millisecondsTimeout, /// </summary>
bool exitContext, /// <param name="callback">A callback to execute</param>
WaitHandle cancelWaitHandle, /// <param name="state">
out Exception e); /// The context object of the work item. Used for passing arguments to the work item.
/// </param>
/// <summary> /// <param name="postExecuteWorkItemCallback">
/// Get the result of the work item. /// A delegate to call after the callback completion
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. /// </param>
/// </summary> /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
/// <returns>The result of the work item</returns> /// <returns>Returns a work item result</returns>
/// <param name="e">Filled with the exception if one was thrown</param> IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException /// <summary>
object GetResult( /// Queue a work item
TimeSpan timeout, /// </summary>
bool exitContext, /// <param name="callback">A callback to execute</param>
WaitHandle cancelWaitHandle, /// <param name="state">
out Exception e); /// The context object of the work item. Used for passing arguments to the work item.
/// </param>
/// <summary> /// <param name="postExecuteWorkItemCallback">
/// Gets an indication whether the asynchronous operation has completed. /// A delegate to call after the callback completion
/// </summary> /// </param>
bool IsCompleted { get; } /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
/// <param name="workItemPriority">The work item priority</param>
/// <summary> /// <returns>Returns a work item result</returns>
/// Gets an indication whether the asynchronous operation has been canceled. IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
/// </summary>
bool IsCanceled { get; } /// <summary>
/// Queue a work item
/// <summary> /// </summary>
/// Gets a user-defined object that qualifies or contains information about an asynchronous operation. /// <param name="workItemInfo">Work item info</param>
/// </summary> /// <param name="callback">A callback to execute</param>
object State { get; } /// <returns>Returns a work item result</returns>
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
/// <summary>
/// Cancel the work item if it didn't start running yet. /// <summary>
/// </summary> /// Queue a work item
/// <returns>Returns true on success or false if the work item is in progress or already completed</returns> /// </summary>
bool Cancel(); /// <param name="workItemInfo">Work item information</param>
/// <param name="callback">A callback to execute</param>
/// <summary> /// <param name="state">
/// Get the work item's priority /// The context object of the work item. Used for passing arguments to the work item.
/// </summary> /// </param>
WorkItemPriority WorkItemPriority { get; } /// <returns>Returns a work item result</returns>
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
/// <summary>
/// Return the result, same as GetResult() #endregion
/// </summary>
object Result { get; } #region QueueWorkItem(Action<...>)
/// <summary> /// <summary>
/// Returns the exception if occured otherwise returns null. /// Queue a work item.
/// </summary> /// </summary>
object Exception { get; } /// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
} IWorkItemResult QueueWorkItem(Action action);
#endregion /// <summary>
} /// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg, WorkItemPriority priority);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T> (Action<T> action, T arg);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T1, T2> (Action<T1, T2> action, T1 arg1, T2 arg2, WorkItemPriority priority);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T1, T2, T3> (Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T1, T2, T3, T4> (Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority);
#endregion
#region QueueWorkItem(Func<...>)
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
/// its GetResult() returns a TResult object</returns>
IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
/// its GetResult() returns a TResult object</returns>
IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
/// its GetResult() returns a TResult object</returns>
IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
/// its GetResult() returns a TResult object</returns>
IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult&lt;TResult&gt; object.
/// its GetResult() returns a TResult object</returns>
IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
#endregion
}
#endregion
#region CallToPostExecute enumerator
[Flags]
public enum CallToPostExecute
{
/// <summary>
/// Never call to the PostExecute call back
/// </summary>
Never = 0x00,
/// <summary>
/// Call to the PostExecute only when the work item is cancelled
/// </summary>
WhenWorkItemCanceled = 0x01,
/// <summary>
/// Call to the PostExecute only when the work item is not cancelled
/// </summary>
WhenWorkItemNotCanceled = 0x02,
/// <summary>
/// Always call to the PostExecute
/// </summary>
Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
}
#endregion
#region IWorkItemResult interface
/// <summary>
/// The common interface of IWorkItemResult and IWorkItemResult&lt;T&gt;
/// </summary>
public interface IWaitableResult
{
/// <summary>
/// This method intent is for internal use.
/// </summary>
/// <returns></returns>
IWorkItemResult GetWorkItemResult();
/// <summary>
/// This method intent is for internal use.
/// </summary>
/// <returns></returns>
IWorkItemResult<TResult> GetWorkItemResultT<TResult>();
}
/// <summary>
/// IWorkItemResult interface.
/// Created when a WorkItemCallback work item is queued.
/// </summary>
public interface IWorkItemResult : IWorkItemResult<object>
{
}
/// <summary>
/// IWorkItemResult&lt;TResult&gt; interface.
/// Created when a Func&lt;TResult&gt; work item is queued.
/// </summary>
public interface IWorkItemResult<TResult> : IWaitableResult
{
/// <summary>
/// Get the result of the work item.
/// If the work item didn't run yet then the caller waits.
/// </summary>
/// <returns>The result of the work item</returns>
TResult GetResult();
/// <summary>
/// Get the result of the work item.
/// If the work item didn't run yet then the caller waits until timeout.
/// </summary>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
TResult GetResult(
int millisecondsTimeout,
bool exitContext);
/// <summary>
/// Get the result of the work item.
/// If the work item didn't run yet then the caller waits until timeout.
/// </summary>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
TResult GetResult(
TimeSpan timeout,
bool exitContext);
/// <summary>
/// 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.
/// </summary>
/// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
/// <param name="exitContext">
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
/// </param>
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
TResult GetResult(
int millisecondsTimeout,
bool exitContext,
WaitHandle cancelWaitHandle);
/// <summary>
/// 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.
/// </summary>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
TResult GetResult(
TimeSpan timeout,
bool exitContext,
WaitHandle cancelWaitHandle);
/// <summary>
/// Get the result of the work item.
/// If the work item didn't run yet then the caller waits.
/// </summary>
/// <param name="e">Filled with the exception if one was thrown</param>
/// <returns>The result of the work item</returns>
TResult GetResult(out Exception e);
/// <summary>
/// Get the result of the work item.
/// If the work item didn't run yet then the caller waits until timeout.
/// </summary>
/// <param name="millisecondsTimeout"></param>
/// <param name="exitContext"></param>
/// <param name="e">Filled with the exception if one was thrown</param>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
TResult GetResult(
int millisecondsTimeout,
bool exitContext,
out Exception e);
/// <summary>
/// Get the result of the work item.
/// If the work item didn't run yet then the caller waits until timeout.
/// </summary>
/// <param name="exitContext"></param>
/// <param name="e">Filled with the exception if one was thrown</param>
/// <param name="timeout"></param>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
TResult GetResult(
TimeSpan timeout,
bool exitContext,
out Exception e);
/// <summary>
/// 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.
/// </summary>
/// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
/// <param name="exitContext">
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
/// </param>
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
/// <param name="e">Filled with the exception if one was thrown</param>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
TResult GetResult(
int millisecondsTimeout,
bool exitContext,
WaitHandle cancelWaitHandle,
out Exception e);
/// <summary>
/// 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.
/// </summary>
/// <returns>The result of the work item</returns>
/// <param name="cancelWaitHandle"></param>
/// <param name="e">Filled with the exception if one was thrown</param>
/// <param name="timeout"></param>
/// <param name="exitContext"></param>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
TResult GetResult(
TimeSpan timeout,
bool exitContext,
WaitHandle cancelWaitHandle,
out Exception e);
/// <summary>
/// Gets an indication whether the asynchronous operation has completed.
/// </summary>
bool IsCompleted { get; }
/// <summary>
/// Gets an indication whether the asynchronous operation has been canceled.
/// </summary>
bool IsCanceled { get; }
/// <summary>
/// Gets the user-defined object that contains context data
/// for the work item method.
/// </summary>
object State { get; }
/// <summary>
/// Same as Cancel(false).
/// </summary>
bool Cancel();
/// <summary>
/// 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
/// </summary>
/// <param name="abortExecution">When true send an AbortException to the executing thread.</param>
/// <returns>Returns true if the work item was not completed, otherwise false.</returns>
bool Cancel(bool abortExecution);
/// <summary>
/// Get the work item's priority
/// </summary>
WorkItemPriority WorkItemPriority { get; }
/// <summary>
/// Return the result, same as GetResult()
/// </summary>
TResult Result { get; }
/// <summary>
/// Returns the exception if occured otherwise returns null.
/// </summary>
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, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
public delegate TResult Func<TResult>();
public delegate TResult Func<T, TResult>(T arg1);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
#endregion
}

View File

@ -0,0 +1,27 @@

namespace Amib.Threading.Internal
{
/// <summary>
/// An internal delegate to call when the WorkItem starts or completes
/// </summary>
internal delegate void WorkItemStateCallback(WorkItem workItem);
internal interface IInternalWorkItemResult
{
event WorkItemStateCallback OnWorkItemStarted;
event WorkItemStateCallback OnWorkItemCompleted;
}
internal interface IInternalWaitableResult
{
/// <summary>
/// This method is intent for internal use.
/// </summary>
IWorkItemResult GetWorkItemResult();
}
public interface IHasWorkItemPriority
{
WorkItemPriority WorkItemPriority { get; }
}
}

View File

@ -1,240 +1,239 @@
// Ami Bar using System;
// amibar@gmail.com using System.Collections;
using System.Collections.Generic;
using System; using System.Diagnostics;
using System.Collections;
using System.Diagnostics; namespace Amib.Threading.Internal
{
namespace Amib.Threading.Internal #region PriorityQueue class
{
#region PriorityQueue class /// <summary>
/// PriorityQueue class
/// <summary> /// This class is not thread safe because we use external lock
/// PriorityQueue class /// </summary>
/// This class is not thread safe because we use external lock public sealed class PriorityQueue : IEnumerable
/// </summary> {
public sealed class PriorityQueue : IEnumerable #region Private members
{
#region Private members /// <summary>
/// The number of queues, there is one for each type of priority
/// <summary> /// </summary>
/// The number of queues, there is one for each type of priority private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1;
/// </summary>
private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; /// <summary>
/// Work items queues. There is one for each type of priority
/// <summary> /// </summary>
/// Work items queues. There is one for each type of priority private readonly LinkedList<IHasWorkItemPriority>[] _queues = new LinkedList<IHasWorkItemPriority>[_queuesCount];
/// </summary>
private Queue [] _queues = new Queue[_queuesCount]; /// <summary>
/// The total number of work items within the queues
/// <summary> /// </summary>
/// The total number of work items within the queues private int _workItemsCount;
/// </summary>
private int _workItemsCount = 0; /// <summary>
/// Use with IEnumerable interface
/// <summary> /// </summary>
/// Use with IEnumerable interface private int _version;
/// </summary>
private int _version = 0; #endregion
#endregion #region Contructor
#region Contructor public PriorityQueue()
{
public PriorityQueue() for(int i = 0; i < _queues.Length; ++i)
{ {
for(int i = 0; i < _queues.Length; ++i) _queues[i] = new LinkedList<IHasWorkItemPriority>();
{ }
_queues[i] = new Queue(); }
}
} #endregion
#endregion #region Methods
#region Methods /// <summary>
/// Enqueue a work item.
/// <summary> /// </summary>
/// Enqueue a work item. /// <param name="workItem">A work item</param>
/// </summary> public void Enqueue(IHasWorkItemPriority workItem)
/// <param name="workItem">A work item</param> {
public void Enqueue(IHasWorkItemPriority workItem) Debug.Assert(null != workItem);
{
Debug.Assert(null != workItem); int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1;
Debug.Assert(queueIndex >= 0);
int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; Debug.Assert(queueIndex < _queuesCount);
Debug.Assert(queueIndex >= 0);
Debug.Assert(queueIndex < _queuesCount); _queues[queueIndex].AddLast(workItem);
++_workItemsCount;
_queues[queueIndex].Enqueue(workItem); ++_version;
++_workItemsCount; }
++_version;
} /// <summary>
/// Dequeque a work item.
/// <summary> /// </summary>
/// Dequeque a work item. /// <returns>Returns the next work item</returns>
/// </summary> public IHasWorkItemPriority Dequeue()
/// <returns>Returns the next work item</returns> {
public IHasWorkItemPriority Dequeue() IHasWorkItemPriority workItem = null;
{
IHasWorkItemPriority workItem = null; if(_workItemsCount > 0)
{
if(_workItemsCount > 0) int queueIndex = GetNextNonEmptyQueue(-1);
{ Debug.Assert(queueIndex >= 0);
int queueIndex = GetNextNonEmptyQueue(-1); workItem = _queues[queueIndex].First.Value;
Debug.Assert(queueIndex >= 0); _queues[queueIndex].RemoveFirst();
workItem = _queues[queueIndex].Dequeue() as IHasWorkItemPriority; Debug.Assert(null != workItem);
Debug.Assert(null != workItem); --_workItemsCount;
--_workItemsCount; ++_version;
++_version; }
}
return workItem;
return workItem; }
}
/// <summary>
/// <summary> /// Find the next non empty queue starting at queue queueIndex+1
/// Find the next non empty queue starting at queue queueIndex+1 /// </summary>
/// </summary> /// <param name="queueIndex">The index-1 to start from</param>
/// <param name="queueIndex">The index-1 to start from</param> /// <returns>
/// <returns> /// The index of the next non empty queue or -1 if all the queues are empty
/// The index of the next non empty queue or -1 if all the queues are empty /// </returns>
/// </returns> private int GetNextNonEmptyQueue(int queueIndex)
private int GetNextNonEmptyQueue(int queueIndex) {
{ for(int i = queueIndex+1; i < _queuesCount; ++i)
for(int i = queueIndex+1; i < _queuesCount; ++i) {
{ if(_queues[i].Count > 0)
if(_queues[i].Count > 0) {
{ return i;
return i; }
} }
} return -1;
return -1; }
}
/// <summary>
/// <summary> /// The number of work items
/// The number of work items /// </summary>
/// </summary> public int Count
public int Count {
{ get
get {
{ return _workItemsCount;
return _workItemsCount; }
} }
}
/// <summary>
/// <summary> /// Clear all the work items
/// Clear all the work items /// </summary>
/// </summary> public void Clear()
public void Clear() {
{ if (_workItemsCount > 0)
if (_workItemsCount > 0) {
{ foreach(LinkedList<IHasWorkItemPriority> queue in _queues)
foreach(Queue queue in _queues) {
{ queue.Clear();
queue.Clear(); }
} _workItemsCount = 0;
_workItemsCount = 0; ++_version;
++_version; }
} }
}
#endregion
#endregion
#region IEnumerable Members
#region IEnumerable Members
/// <summary>
/// <summary> /// Returns an enumerator to iterate over the work items
/// Returns an enumerator to iterate over the work items /// </summary>
/// </summary> /// <returns>Returns an enumerator</returns>
/// <returns>Returns an enumerator</returns> public IEnumerator GetEnumerator()
public IEnumerator GetEnumerator() {
{ return new PriorityQueueEnumerator(this);
return new PriorityQueueEnumerator(this); }
}
#endregion
#endregion
#region PriorityQueueEnumerator
#region PriorityQueueEnumerator
/// <summary>
/// <summary> /// The class the implements the enumerator
/// The class the implements the enumerator /// </summary>
/// </summary> private class PriorityQueueEnumerator : IEnumerator
private class PriorityQueueEnumerator : IEnumerator {
{ private readonly PriorityQueue _priorityQueue;
private PriorityQueue _priorityQueue; private int _version;
private int _version; private int _queueIndex;
private int _queueIndex; private IEnumerator _enumerator;
private IEnumerator _enumerator;
public PriorityQueueEnumerator(PriorityQueue priorityQueue)
public PriorityQueueEnumerator(PriorityQueue priorityQueue) {
{ _priorityQueue = priorityQueue;
_priorityQueue = priorityQueue; _version = _priorityQueue._version;
_version = _priorityQueue._version; _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); if (_queueIndex >= 0)
if (_queueIndex >= 0) {
{ _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); }
} else
else {
{ _enumerator = null;
_enumerator = null; }
} }
}
#region IEnumerator Members
#region IEnumerator Members
public void Reset()
public void Reset() {
{ _version = _priorityQueue._version;
_version = _priorityQueue._version; _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); if (_queueIndex >= 0)
if (_queueIndex >= 0) {
{ _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); }
} else
else {
{ _enumerator = null;
_enumerator = null; }
} }
}
public object Current
public object Current {
{ get
get {
{ Debug.Assert(null != _enumerator);
Debug.Assert(null != _enumerator); return _enumerator.Current;
return _enumerator.Current; }
} }
}
public bool MoveNext()
public bool MoveNext() {
{ if (null == _enumerator)
if (null == _enumerator) {
{ return false;
return false; }
}
if(_version != _priorityQueue._version)
if(_version != _priorityQueue._version) {
{ throw new InvalidOperationException("The collection has been modified");
throw new InvalidOperationException("The collection has been modified");
}
} if (!_enumerator.MoveNext())
if (!_enumerator.MoveNext()) {
{ _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex);
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); if(-1 == _queueIndex)
if(-1 == _queueIndex) {
{ return false;
return false; }
} _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); _enumerator.MoveNext();
_enumerator.MoveNext(); return true;
return true; }
} return true;
return true; }
}
#endregion
#endregion }
}
#endregion
#endregion }
}
#endregion
#endregion }
}

View File

@ -0,0 +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

16
ThirdParty/SmartThreadPool/SLExt.cs vendored Normal file
View File

@ -0,0 +1,16 @@
#if _SILVERLIGHT
using System.Threading;
namespace Amib.Threading
{
public enum ThreadPriority
{
Lowest,
BelowNormal,
Normal,
AboveNormal,
Highest,
}
}
#endif

View File

@ -0,0 +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
}
#endif

View File

@ -1,354 +1,448 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading;
namespace Amib.Threading.Internal
{ namespace Amib.Threading
internal enum STPPerformanceCounterType {
{ public interface ISTPPerformanceCountersReader
// Fields {
ActiveThreads = 0, long InUseThreads { get; }
InUseThreads = 1, long ActiveThreads { get; }
OverheadThreads = 2, long WorkItemsQueued { get; }
OverheadThreadsPercent = 3, long WorkItemsProcessed { get; }
OverheadThreadsPercentBase = 4, }
}
WorkItems = 5,
WorkItemsInQueue = 6, namespace Amib.Threading.Internal
WorkItemsProcessed = 7, {
internal interface ISTPInstancePerformanceCounters : IDisposable
WorkItemsQueuedPerSecond = 8, {
WorkItemsProcessedPerSecond = 9, void Close();
void SampleThreads(long activeThreads, long inUseThreads);
AvgWorkItemWaitTime = 10, void SampleWorkItems(long workItemsQueued, long workItemsProcessed);
AvgWorkItemWaitTimeBase = 11, void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime);
void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime);
AvgWorkItemProcessTime = 12, }
AvgWorkItemProcessTimeBase = 13, #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
WorkItemsGroups = 14, internal enum STPPerformanceCounterType
{
LastCounter = 14, // Fields
} ActiveThreads = 0,
InUseThreads = 1,
OverheadThreads = 2,
/// <summary> OverheadThreadsPercent = 3,
/// Summary description for STPPerformanceCounter. OverheadThreadsPercentBase = 4,
/// </summary>
internal class STPPerformanceCounter WorkItems = 5,
{ WorkItemsInQueue = 6,
// Fields WorkItemsProcessed = 7,
private PerformanceCounterType _pcType;
protected string _counterHelp; WorkItemsQueuedPerSecond = 8,
protected string _counterName; WorkItemsProcessedPerSecond = 9,
// Methods AvgWorkItemWaitTime = 10,
public STPPerformanceCounter( AvgWorkItemWaitTimeBase = 11,
string counterName,
string counterHelp, AvgWorkItemProcessTime = 12,
PerformanceCounterType pcType) AvgWorkItemProcessTimeBase = 13,
{
this._counterName = counterName; WorkItemsGroups = 14,
this._counterHelp = counterHelp;
this._pcType = pcType; LastCounter = 14,
} }
public void AddCounterToCollection(CounterCreationDataCollection counterData)
{ /// <summary>
CounterCreationData counterCreationData = new CounterCreationData( /// Summary description for STPPerformanceCounter.
_counterName, /// </summary>
_counterHelp, internal class STPPerformanceCounter
_pcType); {
// Fields
counterData.Add(counterCreationData); private readonly PerformanceCounterType _pcType;
} protected string _counterHelp;
protected string _counterName;
// Properties
public string Name // Methods
{ public STPPerformanceCounter(
get string counterName,
{ string counterHelp,
return _counterName; PerformanceCounterType pcType)
} {
} _counterName = counterName;
} _counterHelp = counterHelp;
_pcType = pcType;
internal class STPPerformanceCounters }
{
// Fields public void AddCounterToCollection(CounterCreationDataCollection counterData)
internal STPPerformanceCounter[] _stpPerformanceCounters; {
private static STPPerformanceCounters _instance; CounterCreationData counterCreationData = new CounterCreationData(
internal const string _stpCategoryHelp = "SmartThreadPool performance counters"; _counterName,
internal const string _stpCategoryName = "SmartThreadPool"; _counterHelp,
_pcType);
// Methods
static STPPerformanceCounters() counterData.Add(counterCreationData);
{ }
_instance = new STPPerformanceCounters();
} // Properties
public string Name
private STPPerformanceCounters() {
{ get
STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] {
{ return _counterName;
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), internal class STPPerformanceCounters
{
new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), // Fields
new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), internal STPPerformanceCounter[] _stpPerformanceCounters;
new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), private static readonly STPPerformanceCounters _instance;
internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), internal const string _stpCategoryName = "SmartThreadPool";
new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32),
// Methods
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), static STPPerformanceCounters()
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), {
_instance = new STPPerformanceCounters();
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),
private STPPerformanceCounters()
new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), {
}; STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[]
{
_stpPerformanceCounters = stpPerformanceCounters; new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32),
SetupCategory(); 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),
private void SetupCategory() new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase),
{
if (!PerformanceCounterCategory.Exists(_stpCategoryName)) 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),
CounterCreationDataCollection counters = new CounterCreationDataCollection(); new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32),
for (int i = 0; i < _stpPerformanceCounters.Length; i++) 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),
_stpPerformanceCounters[i].AddCounterToCollection(counters);
} 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),
// *********** Remark for .NET 2.0 *********** new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64),
// If you are here, it means you got the warning that this overload new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase),
// of the method is deprecated in .NET 2.0. To use the correct
// method overload, uncomment the third argument of new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32),
// the method. };
#pragma warning disable 0618
PerformanceCounterCategory.Create( _stpPerformanceCounters = stpPerformanceCounters;
_stpCategoryName, SetupCategory();
_stpCategoryHelp, }
//PerformanceCounterCategoryType.MultiInstance,
counters); private void SetupCategory()
#pragma warning restore 0618 {
} if (!PerformanceCounterCategory.Exists(_stpCategoryName))
} {
CounterCreationDataCollection counters = new CounterCreationDataCollection();
// Properties
public static STPPerformanceCounters Instance for (int i = 0; i < _stpPerformanceCounters.Length; i++)
{ {
get _stpPerformanceCounters[i].AddCounterToCollection(counters);
{ }
return _instance;
} PerformanceCounterCategory.Create(
} _stpCategoryName,
} _stpCategoryHelp,
PerformanceCounterCategoryType.MultiInstance,
internal class STPInstancePerformanceCounter : IDisposable counters);
{
// Fields }
private PerformanceCounter _pcs; }
// Methods // Properties
protected STPInstancePerformanceCounter() public static STPPerformanceCounters Instance
{ {
} get
{
public STPInstancePerformanceCounter( return _instance;
string instance, }
STPPerformanceCounterType spcType) }
{ }
STPPerformanceCounters counters = STPPerformanceCounters.Instance;
_pcs = new PerformanceCounter( internal class STPInstancePerformanceCounter : IDisposable
STPPerformanceCounters._stpCategoryName, {
counters._stpPerformanceCounters[(int) spcType].Name, // Fields
instance, private bool _isDisposed;
false); private PerformanceCounter _pcs;
_pcs.RawValue = _pcs.RawValue;
} // Methods
protected STPInstancePerformanceCounter()
~STPInstancePerformanceCounter() {
{ _isDisposed = false;
Close(); }
}
public STPInstancePerformanceCounter(
public void Close() string instance,
{ STPPerformanceCounterType spcType) : this()
if (_pcs != null) {
{ STPPerformanceCounters counters = STPPerformanceCounters.Instance;
_pcs.RemoveInstance(); _pcs = new PerformanceCounter(
_pcs.Close(); STPPerformanceCounters._stpCategoryName,
_pcs = null; counters._stpPerformanceCounters[(int) spcType].Name,
} instance,
} false);
_pcs.RawValue = _pcs.RawValue;
public void Dispose() }
{
Close();
GC.SuppressFinalize(this); public void Close()
} {
if (_pcs != null)
public virtual void Increment() {
{ _pcs.RemoveInstance();
_pcs.Increment(); _pcs.Close();
} _pcs = null;
}
public virtual void IncrementBy(long val) }
{
_pcs.IncrementBy(val); public void Dispose()
} {
Dispose(true);
public virtual void Set(long val) }
{
_pcs.RawValue = val; public virtual void Dispose(bool disposing)
} {
} if (!_isDisposed)
{
internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter if (disposing)
{ {
// Methods Close();
public STPInstanceNullPerformanceCounter() {} }
public override void Increment() {} }
public override void IncrementBy(long value) {} _isDisposed = true;
public override void Set(long val) {} }
}
public virtual void Increment()
internal interface ISTPInstancePerformanceCounters : IDisposable {
{ _pcs.Increment();
void Close(); }
void SampleThreads(long activeThreads, long inUseThreads);
void SampleWorkItems(long workItemsQueued, long workItemsProcessed); public virtual void IncrementBy(long val)
void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime); {
void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime); _pcs.IncrementBy(val);
} }
public virtual void Set(long val)
internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable {
{ _pcs.RawValue = val;
// Fields }
private STPInstancePerformanceCounter[] _pcs; }
private static STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter
// Methods {
static STPInstancePerformanceCounters() // Methods
{ public override void Increment() {}
_stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter(); public override void IncrementBy(long value) {}
} public override void Set(long val) {}
}
public STPInstancePerformanceCounters(string instance)
{
_pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
// STPPerformanceCounters counters = STPPerformanceCounters.Instance; internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters
for (int i = 0; i < _pcs.Length; i++) {
{ private bool _isDisposed;
if (instance != null) // Fields
{ private STPInstancePerformanceCounter[] _pcs;
_pcs[i] = new STPInstancePerformanceCounter( private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
instance,
(STPPerformanceCounterType) i); // Methods
} static STPInstancePerformanceCounters()
else {
{ _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter();
_pcs[i] = _stpInstanceNullPerformanceCounter; }
}
} public STPInstancePerformanceCounters(string instance)
} {
_isDisposed = false;
_pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
public void Close()
{ // Call the STPPerformanceCounters.Instance so the static constructor will
if (null != _pcs) // intialize the STPPerformanceCounters singleton.
{ STPPerformanceCounters.Instance.GetHashCode();
for (int i = 0; i < _pcs.Length; i++)
{ for (int i = 0; i < _pcs.Length; i++)
if (null != _pcs[i]) {
{ if (instance != null)
_pcs[i].Close(); {
} _pcs[i] = new STPInstancePerformanceCounter(
} instance,
_pcs = null; (STPPerformanceCounterType) i);
} }
} else
{
~STPInstancePerformanceCounters() _pcs[i] = _stpInstanceNullPerformanceCounter;
{ }
Close(); }
} }
public void Dispose()
{ public void Close()
Close(); {
GC.SuppressFinalize(this); if (null != _pcs)
} {
for (int i = 0; i < _pcs.Length; i++)
private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType) {
{ if (null != _pcs[i])
return _pcs[(int) spcType]; {
} _pcs[i].Dispose();
}
public void SampleThreads(long activeThreads, long inUseThreads) }
{ _pcs = null;
GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads); }
GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads); }
GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads);
public void Dispose()
GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads); {
GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads); Dispose(true);
} }
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) public virtual void Dispose(bool disposing)
{ {
GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed); if (!_isDisposed)
GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued); {
GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed); if (disposing)
{
GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued); Close();
GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed); }
} }
_isDisposed = true;
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) }
{
GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds); private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment(); {
} return _pcs[(int) spcType];
}
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
{ public void SampleThreads(long activeThreads, long inUseThreads)
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds); {
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment(); GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads);
} GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads);
} GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads);
internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads);
{ GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads);
static NullSTPInstancePerformanceCounters() }
{
} public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
{
private static NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(null); GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed);
GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued);
public static NullSTPInstancePerformanceCounters Instance GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed);
{
get { return _instance; } GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued);
} GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed);
}
public NullSTPInstancePerformanceCounters(string instance) {}
public void Close() {} public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
public void Dispose() {} {
GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds);
public void SampleThreads(long activeThreads, long inUseThreads) {} GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment();
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {} }
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {} 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
}
}
}

View File

@ -1,113 +1,212 @@
// Ami Bar using System;
// amibar@gmail.com using System.Threading;
using System.Threading; namespace Amib.Threading
{
namespace Amib.Threading /// <summary>
{ /// Summary description for STPStartInfo.
/// <summary> /// </summary>
/// Summary description for STPStartInfo. public class STPStartInfo : WIGStartInfo
/// </summary> {
public class STPStartInfo : WIGStartInfo private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
{ private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
/// <summary> private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
/// Idle timeout in milliseconds. #if !(WINDOWS_PHONE)
/// If a thread is idle for _idleTimeout milliseconds then private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority;
/// it may quit. #endif
/// </summary> private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
private int _idleTimeout; private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground;
private bool _enableLocalPerformanceCounters;
/// <summary> private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName;
/// The lower limit of threads in the pool. private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize;
/// </summary>
private int _minWorkerThreads; public STPStartInfo()
{
/// <summary> _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
/// The upper limit of threads in the pool. #if !(WINDOWS_PHONE)
/// </summary> _threadPriority = SmartThreadPool.DefaultThreadPriority;
private int _maxWorkerThreads; #endif
_maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
/// <summary> _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
/// The priority of the threads in the pool _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
/// </summary> }
private ThreadPriority _threadPriority;
public STPStartInfo(STPStartInfo stpStartInfo)
/// <summary> : base(stpStartInfo)
/// The thread pool name. Threads will get names depending on this. {
/// </summary> _idleTimeout = stpStartInfo.IdleTimeout;
private string _threadPoolName; _minWorkerThreads = stpStartInfo.MinWorkerThreads;
_maxWorkerThreads = stpStartInfo.MaxWorkerThreads;
/// <summary> #if !(WINDOWS_PHONE)
/// If this field is not null then the performance counters are enabled _threadPriority = stpStartInfo.ThreadPriority;
/// and use the string as the name of the instance. #endif
/// </summary> _performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName;
private string _pcInstanceName; _enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters;
_threadPoolName = stpStartInfo._threadPoolName;
private int _stackSize; _areThreadsBackground = stpStartInfo.AreThreadsBackground;
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
public STPStartInfo() : base() _apartmentState = stpStartInfo._apartmentState;
{ #endif
_idleTimeout = SmartThreadPool.DefaultIdleTimeout; }
_minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
_maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; /// <summary>
_threadPriority = SmartThreadPool.DefaultThreadPriority; /// Get/Set the idle timeout in milliseconds.
_threadPoolName = SmartThreadPool.DefaultThreadPoolName; /// If a thread is idle (starved) longer than IdleTimeout then it may quit.
_pcInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; /// </summary>
_stackSize = SmartThreadPool.DefaultStackSize; public virtual int IdleTimeout
} {
get { return _idleTimeout; }
public STPStartInfo(STPStartInfo stpStartInfo) : base(stpStartInfo) set
{ {
_idleTimeout = stpStartInfo._idleTimeout; ThrowIfReadOnly();
_minWorkerThreads = stpStartInfo._minWorkerThreads; _idleTimeout = value;
_maxWorkerThreads = stpStartInfo._maxWorkerThreads; }
_threadPriority = stpStartInfo._threadPriority; }
_threadPoolName = stpStartInfo._threadPoolName;
_pcInstanceName = stpStartInfo._pcInstanceName;
_stackSize = stpStartInfo._stackSize; /// <summary>
} /// Get/Set the lower limit of threads in the pool.
/// </summary>
public int IdleTimeout public virtual int MinWorkerThreads
{ {
get { return _idleTimeout; } get { return _minWorkerThreads; }
set { _idleTimeout = value; } set
} {
ThrowIfReadOnly();
public int MinWorkerThreads _minWorkerThreads = value;
{ }
get { return _minWorkerThreads; } }
set { _minWorkerThreads = value; }
}
/// <summary>
public int MaxWorkerThreads /// Get/Set the upper limit of threads in the pool.
{ /// </summary>
get { return _maxWorkerThreads; } public virtual int MaxWorkerThreads
set { _maxWorkerThreads = value; } {
} get { return _maxWorkerThreads; }
set
public ThreadPriority ThreadPriority {
{ ThrowIfReadOnly();
get { return _threadPriority; } _maxWorkerThreads = value;
set { _threadPriority = value; } }
} }
public virtual string ThreadPoolName #if !(WINDOWS_PHONE)
{ /// <summary>
get { return _threadPoolName; } /// Get/Set the scheduling priority of the threads in the pool.
set { _threadPoolName = value; } /// The Os handles the scheduling.
} /// </summary>
public virtual ThreadPriority ThreadPriority
{
public string PerformanceCounterInstanceName get { return _threadPriority; }
{ set
get { return _pcInstanceName; } {
set { _pcInstanceName = value; } ThrowIfReadOnly();
} _threadPriority = value;
}
public int StackSize }
{ #endif
get { return _stackSize; } /// <summary>
set { _stackSize = value; } /// Get/Set the thread pool name. Threads will get names depending on this.
} /// </summary>
} public virtual string ThreadPoolName {
} get { return _threadPoolName; }
set
{
ThrowIfReadOnly ();
_threadPoolName = value;
}
}
/// <summary>
/// Get/Set the performance counter instance name of this SmartThreadPool
/// The default is null which indicate not to use performance counters at all.
/// </summary>
public virtual string PerformanceCounterInstanceName
{
get { return _performanceCounterInstanceName; }
set
{
ThrowIfReadOnly();
_performanceCounterInstanceName = value;
}
}
/// <summary>
/// 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.
/// </summary>
public virtual bool EnableLocalPerformanceCounters
{
get { return _enableLocalPerformanceCounters; }
set
{
ThrowIfReadOnly();
_enableLocalPerformanceCounters = value;
}
}
/// <summary>
/// Get/Set backgroundness of thread in thread pool.
/// </summary>
public virtual bool AreThreadsBackground
{
get { return _areThreadsBackground; }
set
{
ThrowIfReadOnly ();
_areThreadsBackground = value;
}
}
/// <summary>
/// Get a readonly version of this STPStartInfo.
/// </summary>
/// <returns>Returns a readonly reference to this STPStartInfo</returns>
public new STPStartInfo AsReadOnly()
{
return new STPStartInfo(this) { _readOnly = true };
}
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState;
/// <summary>
/// Get/Set the apartment state of threads in the thread pool
/// </summary>
public ApartmentState ApartmentState
{
get { return _apartmentState; }
set
{
ThrowIfReadOnly();
_apartmentState = value;
}
}
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
/// <summary>
/// Get/Set the max stack size of threads in the thread pool
/// </summary>
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
}
}

View File

@ -0,0 +1,60 @@

using System;
using Amib.Threading.Internal;
namespace Amib.Threading
{
public partial class SmartThreadPool
{
#region ThreadEntry class
internal class ThreadEntry
{
/// <summary>
/// The thread creation time
/// The value is stored as UTC value.
/// </summary>
private readonly DateTime _creationTime;
/// <summary>
/// The last time this thread has been running
/// It is updated by IAmAlive() method
/// The value is stored as UTC value.
/// </summary>
private DateTime _lastAliveTime;
/// <summary>
/// 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.
/// </summary>
private readonly SmartThreadPool _associatedSmartThreadPool;
/// <summary>
/// A reference to the current work item a thread from the thread pool
/// is executing.
/// </summary>
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
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
using System.Collections.Generic;
namespace Amib.Threading.Internal
{
internal class SynchronizedDictionary<TKey, TValue>
{
private readonly Dictionary<TKey, TValue> _dictionary;
private readonly object _lock;
public SynchronizedDictionary()
{
_lock = new object();
_dictionary = new Dictionary<TKey, TValue>();
}
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<TKey, TValue>.KeyCollection Keys
{
get
{
lock (_lock)
{
return _dictionary.Keys;
}
}
}
public Dictionary<TKey, TValue>.ValueCollection Values
{
get
{
lock (_lock)
{
return _dictionary.Values;
}
}
}
public void Clear()
{
lock (_lock)
{
_dictionary.Clear();
}
}
}
}

View File

@ -1,99 +1,171 @@
// Ami Bar using System;
// amibar@gmail.com
namespace Amib.Threading
namespace Amib.Threading {
{ /// <summary>
/// <summary> /// Summary description for WIGStartInfo.
/// Summary description for WIGStartInfo. /// </summary>
/// </summary> public class WIGStartInfo
public class WIGStartInfo {
{ private bool _useCallerCallContext;
/// <summary> private bool _useCallerHttpContext;
/// Use the caller's security context private bool _disposeOfStateObjects;
/// </summary> private CallToPostExecute _callToPostExecute;
private bool _useCallerCallContext; private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
private bool _startSuspended;
/// <summary> private WorkItemPriority _workItemPriority;
/// Use the caller's HTTP context private bool _fillStateWithArgs;
/// </summary>
private bool _useCallerHttpContext; protected bool _readOnly;
/// <summary> public WIGStartInfo()
/// Dispose of the state object of a work item {
/// </summary> _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs;
private bool _disposeOfStateObjects; _workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
_startSuspended = SmartThreadPool.DefaultStartSuspended;
/// <summary> _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
/// The option to run the post execute _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
/// </summary> _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
private CallToPostExecute _callToPostExecute; _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
/// <summary> }
/// A post execute callback to call when none is provided in
/// the QueueWorkItem method. public WIGStartInfo(WIGStartInfo wigStartInfo)
/// </summary> {
private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; _useCallerCallContext = wigStartInfo.UseCallerCallContext;
_useCallerHttpContext = wigStartInfo.UseCallerHttpContext;
/// <summary> _disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
/// Indicate the WorkItemsGroup to suspend the handling of the work items _callToPostExecute = wigStartInfo.CallToPostExecute;
/// until the Start() method is called. _postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
/// </summary> _workItemPriority = wigStartInfo.WorkItemPriority;
private bool _startSuspended; _startSuspended = wigStartInfo.StartSuspended;
_fillStateWithArgs = wigStartInfo.FillStateWithArgs;
public WIGStartInfo() }
{
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; protected void ThrowIfReadOnly()
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; {
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; if (_readOnly)
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; {
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; throw new NotSupportedException("This is a readonly instance and set is not supported");
_startSuspended = SmartThreadPool.DefaultStartSuspended; }
} }
public WIGStartInfo(WIGStartInfo wigStartInfo) /// <summary>
{ /// Get/Set if to use the caller's security context
_useCallerCallContext = wigStartInfo._useCallerCallContext; /// </summary>
_useCallerHttpContext = wigStartInfo._useCallerHttpContext; public virtual bool UseCallerCallContext
_disposeOfStateObjects = wigStartInfo._disposeOfStateObjects; {
_callToPostExecute = wigStartInfo._callToPostExecute; get { return _useCallerCallContext; }
_postExecuteWorkItemCallback = wigStartInfo._postExecuteWorkItemCallback; set
_startSuspended = wigStartInfo._startSuspended; {
} ThrowIfReadOnly();
_useCallerCallContext = value;
public bool UseCallerCallContext }
{ }
get { return _useCallerCallContext; }
set { _useCallerCallContext = value; }
} /// <summary>
/// Get/Set if to use the caller's HTTP context
public bool UseCallerHttpContext /// </summary>
{ public virtual bool UseCallerHttpContext
get { return _useCallerHttpContext; } {
set { _useCallerHttpContext = value; } get { return _useCallerHttpContext; }
} set
{
public bool DisposeOfStateObjects ThrowIfReadOnly();
{ _useCallerHttpContext = value;
get { return _disposeOfStateObjects; } }
set { _disposeOfStateObjects = value; } }
}
public CallToPostExecute CallToPostExecute /// <summary>
{ /// Get/Set if to dispose of the state object of a work item
get { return _callToPostExecute; } /// </summary>
set { _callToPostExecute = value; } public virtual bool DisposeOfStateObjects
} {
get { return _disposeOfStateObjects; }
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback set
{ {
get { return _postExecuteWorkItemCallback; } ThrowIfReadOnly();
set { _postExecuteWorkItemCallback = value; } _disposeOfStateObjects = value;
} }
}
public bool StartSuspended
{
get { return _startSuspended; } /// <summary>
set { _startSuspended = value; } /// Get/Set the run the post execute options
} /// </summary>
} public virtual CallToPostExecute CallToPostExecute
} {
get { return _callToPostExecute; }
set
{
ThrowIfReadOnly();
_callToPostExecute = value;
}
}
/// <summary>
/// Get/Set the default post execute callback
/// </summary>
public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback
{
get { return _postExecuteWorkItemCallback; }
set
{
ThrowIfReadOnly();
_postExecuteWorkItemCallback = value;
}
}
/// <summary>
/// Get/Set if the work items execution should be suspended until the Start()
/// method is called.
/// </summary>
public virtual bool StartSuspended
{
get { return _startSuspended; }
set
{
ThrowIfReadOnly();
_startSuspended = value;
}
}
/// <summary>
/// Get/Set the default priority that a work item gets when it is enqueued
/// </summary>
public virtual WorkItemPriority WorkItemPriority
{
get { return _workItemPriority; }
set { _workItemPriority = value; }
}
/// <summary>
/// Get/Set the if QueueWorkItem of Action&lt;...&gt;/Func&lt;...&gt; fill the
/// arguments as an object array into the state of the work item.
/// The arguments can be access later by IWorkItemResult.State.
/// </summary>
public virtual bool FillStateWithArgs
{
get { return _fillStateWithArgs; }
set
{
ThrowIfReadOnly();
_fillStateWithArgs = value;
}
}
/// <summary>
/// Get a readonly version of this WIGStartInfo
/// </summary>
/// <returns>Returns a readonly reference to this WIGStartInfoRO</returns>
public WIGStartInfo AsReadOnly()
{
return new WIGStartInfo(this) { _readOnly = true };
}
}
}

View File

@ -0,0 +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
{
/// <summary>
/// A back reference to the work item
/// </summary>
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;
}
}
/// <summary>
/// Return the result, same as GetResult()
/// </summary>
public object Result
{
get { return GetResult(); }
}
/// <summary>
/// Returns the exception if occured otherwise returns null.
/// This value is valid only after the work item completed,
/// before that it is always null.
/// </summary>
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<TResult> GetWorkItemResultT<TResult>()
{
return new WorkItemResultTWrapper<TResult>(this);
}
#endregion
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,333 +1,343 @@
// Ami Bar using System;
// amibar@gmail.com
namespace Amib.Threading.Internal
using System; {
#region WorkItemFactory class
namespace Amib.Threading.Internal
{ public class WorkItemFactory
#region WorkItemFactory class {
/// <summary>
public class WorkItemFactory /// Create a new work item
{ /// </summary>
/// <summary> /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
/// Create a new work item /// <param name="wigStartInfo">Work item group start information</param>
/// </summary> /// <param name="callback">A callback to execute</param>
/// <param name="wigStartInfo">Work item group start information</param> /// <returns>Returns a work item</returns>
/// <param name="callback">A callback to execute</param> public static WorkItem CreateWorkItem(
/// <returns>Returns a work item</returns> IWorkItemsGroup workItemsGroup,
public static WorkItem CreateWorkItem( WIGStartInfo wigStartInfo,
IWorkItemsGroup workItemsGroup, WorkItemCallback callback)
WIGStartInfo wigStartInfo, {
WorkItemCallback callback) return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null);
{ }
return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null);
} /// <summary>
/// Create a new work item
/// <summary> /// </summary>
/// Create a new work item /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
/// </summary> /// <param name="wigStartInfo">Work item group start information</param>
/// <param name="wigStartInfo">Work item group start information</param> /// <param name="callback">A callback to execute</param>
/// <param name="callback">A callback to execute</param> /// <param name="workItemPriority">The priority of the work item</param>
/// <param name="workItemPriority">The priority of the work item</param> /// <returns>Returns a work item</returns>
/// <returns>Returns a work item</returns> public static WorkItem CreateWorkItem(
public static WorkItem CreateWorkItem( IWorkItemsGroup workItemsGroup,
IWorkItemsGroup workItemsGroup, WIGStartInfo wigStartInfo,
WIGStartInfo wigStartInfo, WorkItemCallback callback,
WorkItemCallback callback, WorkItemPriority workItemPriority)
WorkItemPriority workItemPriority) {
{ return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority);
return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority); }
}
/// <summary>
/// <summary> /// Create a new work item
/// Create a new work item /// </summary>
/// </summary> /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
/// <param name="wigStartInfo">Work item group start information</param> /// <param name="wigStartInfo">Work item group start information</param>
/// <param name="workItemInfo">Work item info</param> /// <param name="workItemInfo">Work item info</param>
/// <param name="callback">A callback to execute</param> /// <param name="callback">A callback to execute</param>
/// <returns>Returns a work item</returns> /// <returns>Returns a work item</returns>
public static WorkItem CreateWorkItem( public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup, IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo, WIGStartInfo wigStartInfo,
WorkItemInfo workItemInfo, WorkItemInfo workItemInfo,
WorkItemCallback callback) WorkItemCallback callback)
{ {
return CreateWorkItem( return CreateWorkItem(
workItemsGroup, workItemsGroup,
wigStartInfo, wigStartInfo,
workItemInfo, workItemInfo,
callback, callback,
null); null);
} }
/// <summary> /// <summary>
/// Create a new work item /// Create a new work item
/// </summary> /// </summary>
/// <param name="wigStartInfo">Work item group start information</param> /// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
/// <param name="callback">A callback to execute</param> /// <param name="wigStartInfo">Work item group start information</param>
/// <param name="state"> /// <param name="callback">A callback to execute</param>
/// The context object of the work item. Used for passing arguments to the work item. /// <param name="state">
/// </param> /// The context object of the work item. Used for passing arguments to the work item.
/// <returns>Returns a work item</returns> /// </param>
public static WorkItem CreateWorkItem( /// <returns>Returns a work item</returns>
IWorkItemsGroup workItemsGroup, public static WorkItem CreateWorkItem(
WIGStartInfo wigStartInfo, IWorkItemsGroup workItemsGroup,
WorkItemCallback callback, WIGStartInfo wigStartInfo,
object state) WorkItemCallback callback,
{ object state)
ValidateCallback(callback); {
ValidateCallback(callback);
WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
WorkItem workItem = new WorkItem( workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
workItemsGroup,
workItemInfo, WorkItem workItem = new WorkItem(
callback, workItemsGroup,
state); workItemInfo,
return workItem; callback,
} state);
return workItem;
/// <summary> }
/// Create a new work item
/// </summary> /// <summary>
/// <param name="wigStartInfo">Work item group start information</param> /// Create a new work item
/// <param name="callback">A callback to execute</param> /// </summary>
/// <param name="state"> /// <param name="workItemsGroup">The work items group</param>
/// The context object of the work item. Used for passing arguments to the work item. /// <param name="wigStartInfo">Work item group start information</param>
/// </param> /// <param name="callback">A callback to execute</param>
/// <param name="workItemPriority">The work item priority</param> /// <param name="state">
/// <returns>Returns a work item</returns> /// The context object of the work item. Used for passing arguments to the work item.
public static WorkItem CreateWorkItem( /// </param>
IWorkItemsGroup workItemsGroup, /// <param name="workItemPriority">The work item priority</param>
WIGStartInfo wigStartInfo, /// <returns>Returns a work item</returns>
WorkItemCallback callback, public static WorkItem CreateWorkItem(
object state, IWorkItemsGroup workItemsGroup,
WorkItemPriority workItemPriority) WIGStartInfo wigStartInfo,
{ WorkItemCallback callback,
ValidateCallback(callback); object state,
WorkItemPriority workItemPriority)
WorkItemInfo workItemInfo = new WorkItemInfo(); {
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; ValidateCallback(callback);
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo.WorkItemPriority = workItemPriority; workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
WorkItem workItem = new WorkItem( workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
workItemsGroup, workItemInfo.WorkItemPriority = workItemPriority;
workItemInfo,
callback, WorkItem workItem = new WorkItem(
state); workItemsGroup,
workItemInfo,
return workItem; callback,
} state);
/// <summary> return workItem;
/// Create a new work item }
/// </summary>
/// <param name="wigStartInfo">Work item group start information</param> /// <summary>
/// <param name="workItemInfo">Work item information</param> /// Create a new work item
/// <param name="callback">A callback to execute</param> /// </summary>
/// <param name="state"> /// <param name="workItemsGroup">The work items group</param>
/// The context object of the work item. Used for passing arguments to the work item. /// <param name="wigStartInfo">Work item group start information</param>
/// </param> /// <param name="workItemInfo">Work item information</param>
/// <returns>Returns a work item</returns> /// <param name="callback">A callback to execute</param>
public static WorkItem CreateWorkItem( /// <param name="state">
IWorkItemsGroup workItemsGroup, /// The context object of the work item. Used for passing arguments to the work item.
WIGStartInfo wigStartInfo, /// </param>
WorkItemInfo workItemInfo, /// <returns>Returns a work item</returns>
WorkItemCallback callback, public static WorkItem CreateWorkItem(
object state) IWorkItemsGroup workItemsGroup,
{ WIGStartInfo wigStartInfo,
ValidateCallback(callback); WorkItemInfo workItemInfo,
ValidateCallback(workItemInfo.PostExecuteWorkItemCallback); WorkItemCallback callback,
object state)
WorkItem workItem = new WorkItem( {
workItemsGroup, ValidateCallback(callback);
new WorkItemInfo(workItemInfo), ValidateCallback(workItemInfo.PostExecuteWorkItemCallback);
callback,
state); WorkItem workItem = new WorkItem(
workItemsGroup,
return workItem; new WorkItemInfo(workItemInfo),
} callback,
state);
/// <summary>
/// Create a new work item return workItem;
/// </summary> }
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="callback">A callback to execute</param> /// <summary>
/// <param name="state"> /// Create a new work item
/// The context object of the work item. Used for passing arguments to the work item. /// </summary>
/// </param> /// <param name="workItemsGroup">The work items group</param>
/// <param name="postExecuteWorkItemCallback"> /// <param name="wigStartInfo">Work item group start information</param>
/// A delegate to call after the callback completion /// <param name="callback">A callback to execute</param>
/// </param> /// <param name="state">
/// <returns>Returns a work item</returns> /// The context object of the work item. Used for passing arguments to the work item.
public static WorkItem CreateWorkItem( /// </param>
IWorkItemsGroup workItemsGroup, /// <param name="postExecuteWorkItemCallback">
WIGStartInfo wigStartInfo, /// A delegate to call after the callback completion
WorkItemCallback callback, /// </param>
object state, /// <returns>Returns a work item</returns>
PostExecuteWorkItemCallback postExecuteWorkItemCallback) public static WorkItem CreateWorkItem(
{ IWorkItemsGroup workItemsGroup,
ValidateCallback(callback); WIGStartInfo wigStartInfo,
ValidateCallback(postExecuteWorkItemCallback); WorkItemCallback callback,
object state,
WorkItemInfo workItemInfo = new WorkItemInfo(); PostExecuteWorkItemCallback postExecuteWorkItemCallback)
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; {
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; ValidateCallback(callback);
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; ValidateCallback(postExecuteWorkItemCallback);
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
WorkItem workItem = new WorkItem( workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemsGroup, workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
workItemInfo, workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
callback, workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
state); workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
return workItem; WorkItem workItem = new WorkItem(
} workItemsGroup,
workItemInfo,
/// <summary> callback,
/// Create a new work item state);
/// </summary>
/// <param name="wigStartInfo">Work item group start information</param> return workItem;
/// <param name="callback">A callback to execute</param> }
/// <param name="state">
/// The context object of the work item. Used for passing arguments to the work item. /// <summary>
/// </param> /// Create a new work item
/// <param name="postExecuteWorkItemCallback"> /// </summary>
/// A delegate to call after the callback completion /// <param name="workItemsGroup">The work items group</param>
/// </param> /// <param name="wigStartInfo">Work item group start information</param>
/// <param name="workItemPriority">The work item priority</param> /// <param name="callback">A callback to execute</param>
/// <returns>Returns a work item</returns> /// <param name="state">
public static WorkItem CreateWorkItem( /// The context object of the work item. Used for passing arguments to the work item.
IWorkItemsGroup workItemsGroup, /// </param>
WIGStartInfo wigStartInfo, /// <param name="postExecuteWorkItemCallback">
WorkItemCallback callback, /// A delegate to call after the callback completion
object state, /// </param>
PostExecuteWorkItemCallback postExecuteWorkItemCallback, /// <param name="workItemPriority">The work item priority</param>
WorkItemPriority workItemPriority) /// <returns>Returns a work item</returns>
{ public static WorkItem CreateWorkItem(
ValidateCallback(callback); IWorkItemsGroup workItemsGroup,
ValidateCallback(postExecuteWorkItemCallback); WIGStartInfo wigStartInfo,
WorkItemCallback callback,
WorkItemInfo workItemInfo = new WorkItemInfo(); object state,
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; PostExecuteWorkItemCallback postExecuteWorkItemCallback,
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; WorkItemPriority workItemPriority)
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; {
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; ValidateCallback(callback);
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; ValidateCallback(postExecuteWorkItemCallback);
workItemInfo.WorkItemPriority = workItemPriority;
WorkItemInfo workItemInfo = new WorkItemInfo();
WorkItem workItem = new WorkItem( workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
workItemsGroup, workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo, workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
callback, workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
state); workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
workItemInfo.WorkItemPriority = workItemPriority;
return workItem;
} WorkItem workItem = new WorkItem(
workItemsGroup,
/// <summary> workItemInfo,
/// Create a new work item callback,
/// </summary> state);
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="callback">A callback to execute</param> return workItem;
/// <param name="state"> }
/// The context object of the work item. Used for passing arguments to the work item.
/// </param> /// <summary>
/// <param name="postExecuteWorkItemCallback"> /// Create a new work item
/// A delegate to call after the callback completion /// </summary>
/// </param> /// <param name="workItemsGroup">The work items group</param>
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> /// <param name="wigStartInfo">Work item group start information</param>
/// <returns>Returns a work item</returns> /// <param name="callback">A callback to execute</param>
public static WorkItem CreateWorkItem( /// <param name="state">
IWorkItemsGroup workItemsGroup, /// The context object of the work item. Used for passing arguments to the work item.
WIGStartInfo wigStartInfo, /// </param>
WorkItemCallback callback, /// <param name="postExecuteWorkItemCallback">
object state, /// A delegate to call after the callback completion
PostExecuteWorkItemCallback postExecuteWorkItemCallback, /// </param>
CallToPostExecute callToPostExecute) /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
{ /// <returns>Returns a work item</returns>
ValidateCallback(callback); public static WorkItem CreateWorkItem(
ValidateCallback(postExecuteWorkItemCallback); IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemInfo workItemInfo = new WorkItemInfo(); WorkItemCallback callback,
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; object state,
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; PostExecuteWorkItemCallback postExecuteWorkItemCallback,
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; CallToPostExecute callToPostExecute)
workItemInfo.CallToPostExecute = callToPostExecute; {
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; ValidateCallback(callback);
ValidateCallback(postExecuteWorkItemCallback);
WorkItem workItem = new WorkItem(
workItemsGroup, WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo, workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
callback, workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
state); workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
workItemInfo.CallToPostExecute = callToPostExecute;
return workItem; workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
} workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
/// <summary> WorkItem workItem = new WorkItem(
/// Create a new work item workItemsGroup,
/// </summary> workItemInfo,
/// <param name="wigStartInfo">Work item group start information</param> callback,
/// <param name="callback">A callback to execute</param> state);
/// <param name="state">
/// The context object of the work item. Used for passing arguments to the work item. return workItem;
/// </param> }
/// <param name="postExecuteWorkItemCallback">
/// A delegate to call after the callback completion /// <summary>
/// </param> /// Create a new work item
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> /// </summary>
/// <param name="workItemPriority">The work item priority</param> /// <param name="workItemsGroup">The work items group</param>
/// <returns>Returns a work item</returns> /// <param name="wigStartInfo">Work item group start information</param>
public static WorkItem CreateWorkItem( /// <param name="callback">A callback to execute</param>
IWorkItemsGroup workItemsGroup, /// <param name="state">
WIGStartInfo wigStartInfo, /// The context object of the work item. Used for passing arguments to the work item.
WorkItemCallback callback, /// </param>
object state, /// <param name="postExecuteWorkItemCallback">
PostExecuteWorkItemCallback postExecuteWorkItemCallback, /// A delegate to call after the callback completion
CallToPostExecute callToPostExecute, /// </param>
WorkItemPriority workItemPriority) /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
{ /// <param name="workItemPriority">The work item priority</param>
/// <returns>Returns a work item</returns>
ValidateCallback(callback); public static WorkItem CreateWorkItem(
ValidateCallback(postExecuteWorkItemCallback); IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemInfo workItemInfo = new WorkItemInfo(); WorkItemCallback callback,
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; object state,
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; PostExecuteWorkItemCallback postExecuteWorkItemCallback,
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; CallToPostExecute callToPostExecute,
workItemInfo.CallToPostExecute = callToPostExecute; WorkItemPriority workItemPriority)
workItemInfo.WorkItemPriority = workItemPriority; {
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
ValidateCallback(callback);
WorkItem workItem = new WorkItem( ValidateCallback(postExecuteWorkItemCallback);
workItemsGroup,
workItemInfo, WorkItemInfo workItemInfo = new WorkItemInfo();
callback, workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
state); workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
return workItem; workItemInfo.CallToPostExecute = callToPostExecute;
} workItemInfo.WorkItemPriority = workItemPriority;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
private static void ValidateCallback(Delegate callback)
{ WorkItem workItem = new WorkItem(
if(callback.GetInvocationList().Length > 1) workItemsGroup,
{ workItemInfo,
throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); callback,
} state);
}
} return workItem;
}
#endregion
} private static void ValidateCallback(Delegate callback)
{
if (callback != null && callback.GetInvocationList().Length > 1)
{
throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
}
}
}
#endregion
}

View File

@ -1,102 +1,69 @@
// Ami Bar namespace Amib.Threading
// amibar@gmail.com {
#region WorkItemInfo class
namespace Amib.Threading
{ /// <summary>
#region WorkItemInfo class /// Summary description for WorkItemInfo.
/// </summary>
/// <summary> public class WorkItemInfo
/// Summary description for WorkItemInfo. {
/// </summary> public WorkItemInfo()
public class WorkItemInfo {
{ UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
/// <summary> UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
/// Use the caller's security context DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
/// </summary> CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
private bool _useCallerCallContext; PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority;
/// <summary> }
/// Use the caller's security context
/// </summary> public WorkItemInfo(WorkItemInfo workItemInfo)
private bool _useCallerHttpContext; {
UseCallerCallContext = workItemInfo.UseCallerCallContext;
/// <summary> UseCallerHttpContext = workItemInfo.UseCallerHttpContext;
/// Dispose of the state object of a work item DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects;
/// </summary> CallToPostExecute = workItemInfo.CallToPostExecute;
private bool _disposeOfStateObjects; PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback;
WorkItemPriority = workItemInfo.WorkItemPriority;
/// <summary> Timeout = workItemInfo.Timeout;
/// The option to run the post execute }
/// </summary>
private CallToPostExecute _callToPostExecute; /// <summary>
/// Get/Set if to use the caller's security context
/// <summary> /// </summary>
/// A post execute callback to call when none is provided in public bool UseCallerCallContext { get; set; }
/// the QueueWorkItem method.
/// </summary> /// <summary>
private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; /// Get/Set if to use the caller's HTTP context
/// </summary>
/// <summary> public bool UseCallerHttpContext { get; set; }
/// The priority of the work item
/// </summary> /// <summary>
private WorkItemPriority _workItemPriority; /// Get/Set if to dispose of the state object of a work item
/// </summary>
public WorkItemInfo() public bool DisposeOfStateObjects { get; set; }
{
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; /// <summary>
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; /// Get/Set the run the post execute options
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; /// </summary>
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; public CallToPostExecute CallToPostExecute { get; set; }
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
_workItemPriority = SmartThreadPool.DefaultWorkItemPriority; /// <summary>
} /// Get/Set the post execute callback
/// </summary>
public WorkItemInfo(WorkItemInfo workItemInfo) public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; }
{
_useCallerCallContext = workItemInfo._useCallerCallContext; /// <summary>
_useCallerHttpContext = workItemInfo._useCallerHttpContext; /// Get/Set the work item's priority
_disposeOfStateObjects = workItemInfo._disposeOfStateObjects; /// </summary>
_callToPostExecute = workItemInfo._callToPostExecute; public WorkItemPriority WorkItemPriority { get; set; }
_postExecuteWorkItemCallback = workItemInfo._postExecuteWorkItemCallback;
_workItemPriority = workItemInfo._workItemPriority; /// <summary>
} /// 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 bool UseCallerCallContext /// </summary>
{ public long Timeout { get; set; }
get { return _useCallerCallContext; } }
set { _useCallerCallContext = value; }
} #endregion
}
public bool UseCallerHttpContext
{
get { return _useCallerHttpContext; }
set { _useCallerHttpContext = value; }
}
public bool DisposeOfStateObjects
{
get { return _disposeOfStateObjects; }
set { _disposeOfStateObjects = value; }
}
public CallToPostExecute CallToPostExecute
{
get { return _callToPostExecute; }
set { _callToPostExecute = value; }
}
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
{
get { return _postExecuteWorkItemCallback; }
set { _postExecuteWorkItemCallback = value; }
}
public WorkItemPriority WorkItemPriority
{
get { return _workItemPriority; }
set { _workItemPriority = value; }
}
}
#endregion
}

View File

@ -0,0 +1,128 @@
using System;
using System.Threading;
namespace Amib.Threading.Internal
{
#region WorkItemResultTWrapper class
internal class WorkItemResultTWrapper<TResult> : IWorkItemResult<TResult>, IInternalWaitableResult
{
private readonly IWorkItemResult _workItemResult;
public WorkItemResultTWrapper(IWorkItemResult workItemResult)
{
_workItemResult = workItemResult;
}
#region IWorkItemResult<TResult> 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<TRes> GetWorkItemResultT<TRes>()
{
return (IWorkItemResult<TRes>)this;
}
#endregion
#endregion
}
#endregion
}

View File

@ -1,512 +1,361 @@
// Ami Bar using System;
// amibar@gmail.com using System.Threading;
using System.Runtime.CompilerServices;
using System; using System.Diagnostics;
using System.Threading;
using System.Runtime.CompilerServices; namespace Amib.Threading.Internal
using System.Diagnostics; {
namespace Amib.Threading.Internal #region WorkItemsGroup class
{
#region WorkItemsGroup class /// <summary>
/// Summary description for WorkItemsGroup.
/// <summary> /// </summary>
/// Summary description for WorkItemsGroup. public class WorkItemsGroup : WorkItemsGroupBase
/// </summary> {
public class WorkItemsGroup : IWorkItemsGroup #region Private members
{
#region Private members private readonly object _lock = new object();
private object _lock = new object(); /// <summary>
/// <summary> /// A reference to the SmartThreadPool instance that created this
/// Contains the name of this instance of SmartThreadPool. /// WorkItemsGroup.
/// Can be changed by the user. /// </summary>
/// </summary> private readonly SmartThreadPool _stp;
private string _name = "WorkItemsGroup";
/// <summary>
/// <summary> /// The OnIdle event
/// A reference to the SmartThreadPool instance that created this /// </summary>
/// WorkItemsGroup. private event WorkItemsGroupIdleHandler _onIdle;
/// </summary>
private SmartThreadPool _stp; /// <summary>
/// A flag to indicate if the Work Items Group is now suspended.
/// <summary> /// </summary>
/// The OnIdle event private bool _isSuspended;
/// </summary>
private event WorkItemsGroupIdleHandler _onIdle; /// <summary>
/// Defines how many work items of this WorkItemsGroup can run at once.
/// <summary> /// </summary>
/// Defines how many work items of this WorkItemsGroup can run at once. private int _concurrency;
/// </summary>
private int _concurrency; /// <summary>
/// Priority queue to hold work items before they are passed
/// <summary> /// to the SmartThreadPool.
/// Priority queue to hold work items before they are passed /// </summary>
/// to the SmartThreadPool. private readonly PriorityQueue _workItemsQueue;
/// </summary>
private PriorityQueue _workItemsQueue; /// <summary>
/// Indicate how many work items are waiting in the SmartThreadPool
/// <summary> /// queue.
/// Indicate how many work items are waiting in the SmartThreadPool /// This value is used to apply the concurrency.
/// queue. /// </summary>
/// This value is used to apply the concurrency. private int _workItemsInStpQueue;
/// </summary>
private int _workItemsInStpQueue; /// <summary>
/// Indicate how many work items are currently running in the SmartThreadPool.
/// <summary> /// This value is used with the Cancel, to calculate if we can send new
/// Indicate how many work items are currently running in the SmartThreadPool. /// work items to the STP.
/// This value is used with the Cancel, to calculate if we can send new /// </summary>
/// work items to the STP. private int _workItemsExecutingInStp = 0;
/// </summary>
private int _workItemsExecutingInStp = 0; /// <summary>
/// WorkItemsGroup start information
/// <summary> /// </summary>
/// WorkItemsGroup start information private readonly WIGStartInfo _workItemsGroupStartInfo;
/// </summary>
private WIGStartInfo _workItemsGroupStartInfo; /// <summary>
/// Signaled when all of the WorkItemsGroup's work item completed.
/// <summary> /// </summary>
/// Signaled when all of the WorkItemsGroup's work item completed. //private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
/// </summary> private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
/// <summary>
/// <summary> /// A common object for all the work items that this work items group
/// A common object for all the work items that this work items group /// generate so we can mark them to cancel in O(1)
/// generate so we can mark them to cancel in O(1) /// </summary>
/// </summary> private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
#endregion
#endregion
#region Construction
#region Construction
public WorkItemsGroup(
public WorkItemsGroup( SmartThreadPool stp,
SmartThreadPool stp, int concurrency,
int concurrency, WIGStartInfo wigStartInfo)
WIGStartInfo wigStartInfo) {
{ if (concurrency <= 0)
if (concurrency <= 0) {
{ throw new ArgumentOutOfRangeException(
throw new ArgumentOutOfRangeException("concurrency", concurrency, "concurrency must be greater than zero"); "concurrency",
} #if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
_stp = stp; concurrency,
_concurrency = concurrency; #endif
_workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo); "concurrency must be greater than zero");
_workItemsQueue = new PriorityQueue(); }
_stp = stp;
// The _workItemsInStpQueue gets the number of currently executing work items, _concurrency = concurrency;
// because once a work item is executing, it cannot be cancelled. _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly();
_workItemsInStpQueue = _workItemsExecutingInStp; _workItemsQueue = new PriorityQueue();
} Name = "WorkItemsGroup";
#endregion // The _workItemsInStpQueue gets the number of currently executing work items,
// because once a work item is executing, it cannot be cancelled.
#region IWorkItemsGroup implementation _workItemsInStpQueue = _workItemsExecutingInStp;
/// <summary> _isSuspended = _workItemsGroupStartInfo.StartSuspended;
/// Get/Set the name of the SmartThreadPool instance }
/// </summary>
public string Name #endregion
{
get #region WorkItemsGroupBase Overrides
{
return _name; public override int Concurrency
} {
get { return _concurrency; }
set set
{ {
_name = value; Debug.Assert(value > 0);
}
} int diff = value - _concurrency;
_concurrency = value;
/// <summary> if (diff > 0)
/// Queue a work item {
/// </summary> EnqueueToSTPNextNWorkItem(diff);
/// <param name="callback">A callback to execute</param> }
/// <returns>Returns a work item result</returns> }
public IWorkItemResult QueueWorkItem(WorkItemCallback callback) }
{
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback); public override int WaitingCallbacks
EnqueueToSTPNextWorkItem(workItem); {
return workItem.GetWorkItemResult(); get { return _workItemsQueue.Count; }
} }
/// <summary> public override object[] GetStates()
/// Queue a work item {
/// </summary> lock (_lock)
/// <param name="callback">A callback to execute</param> {
/// <param name="workItemPriority">The priority of the work item</param> object[] states = new object[_workItemsQueue.Count];
/// <returns>Returns a work item result</returns> int i = 0;
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) foreach (WorkItem workItem in _workItemsQueue)
{ {
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, workItemPriority); states[i] = workItem.GetWorkItemResult().State;
EnqueueToSTPNextWorkItem(workItem); ++i;
return workItem.GetWorkItemResult(); }
} return states;
}
/// <summary> }
/// Queue a work item
/// </summary> /// <summary>
/// <param name="workItemInfo">Work item info</param> /// WorkItemsGroup start information
/// <param name="callback">A callback to execute</param> /// </summary>
/// <returns>Returns a work item result</returns> public override WIGStartInfo WIGStartInfo
public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) {
{ get { return _workItemsGroupStartInfo; }
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback); }
EnqueueToSTPNextWorkItem(workItem);
return workItem.GetWorkItemResult(); /// <summary>
} /// Start the Work Items Group if it was started suspended
/// </summary>
/// <summary> public override void Start()
/// Queue a work item {
/// </summary> // If the Work Items Group already started then quit
/// <param name="callback">A callback to execute</param> if (!_isSuspended)
/// <param name="state"> {
/// The context object of the work item. Used for passing arguments to the work item. return;
/// </param> }
/// <returns>Returns a work item result</returns> _isSuspended = false;
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
{ EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency));
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state); }
EnqueueToSTPNextWorkItem(workItem);
return workItem.GetWorkItemResult(); public override void Cancel(bool abortExecution)
} {
lock (_lock)
/// <summary> {
/// Queue a work item _canceledWorkItemsGroup.IsCanceled = true;
/// </summary> _workItemsQueue.Clear();
/// <param name="callback">A callback to execute</param> _workItemsInStpQueue = 0;
/// <param name="state"> _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
/// The context object of the work item. Used for passing arguments to the work item. }
/// </param>
/// <param name="workItemPriority">The work item priority</param> if (abortExecution)
/// <returns>Returns a work item result</returns> {
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) _stp.CancelAbortWorkItemsGroup(this);
{ }
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, workItemPriority); }
EnqueueToSTPNextWorkItem(workItem);
return workItem.GetWorkItemResult(); /// <summary>
} /// Wait for the thread pool to be idle
/// </summary>
/// <summary> public override bool WaitForIdle(int millisecondsTimeout)
/// Queue a work item {
/// </summary> SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
/// <param name="workItemInfo">Work item information</param> return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
/// <param name="callback">A callback to execute</param> }
/// <param name="state">
/// The context object of the work item. Used for passing arguments to the work item. public override event WorkItemsGroupIdleHandler OnIdle
/// </param> {
/// <returns>Returns a work item result</returns> add { _onIdle += value; }
public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) remove { _onIdle -= value; }
{ }
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback, state);
EnqueueToSTPNextWorkItem(workItem); #endregion
return workItem.GetWorkItemResult();
} #region Private methods
/// <summary> private void RegisterToWorkItemCompletion(IWorkItemResult wir)
/// Queue a work item {
/// </summary> IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir;
/// <param name="callback">A callback to execute</param> iwir.OnWorkItemStarted += OnWorkItemStartedCallback;
/// <param name="state"> iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback;
/// The context object of the work item. Used for passing arguments to the work item. }
/// </param>
/// <param name="postExecuteWorkItemCallback"> public void OnSTPIsStarting()
/// A delegate to call after the callback completion {
/// </param> if (_isSuspended)
/// <returns>Returns a work item result</returns> {
public IWorkItemResult QueueWorkItem( return;
WorkItemCallback callback, }
object state,
PostExecuteWorkItemCallback postExecuteWorkItemCallback) EnqueueToSTPNextNWorkItem(_concurrency);
{ }
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback);
EnqueueToSTPNextWorkItem(workItem); public void EnqueueToSTPNextNWorkItem(int count)
return workItem.GetWorkItemResult(); {
} for (int i = 0; i < count; ++i)
{
/// <summary> EnqueueToSTPNextWorkItem(null, false);
/// Queue a work item }
/// </summary> }
/// <param name="callback">A callback to execute</param>
/// <param name="state"> private object FireOnIdle(object state)
/// The context object of the work item. Used for passing arguments to the work item. {
/// </param> FireOnIdleImpl(_onIdle);
/// <param name="postExecuteWorkItemCallback"> return null;
/// A delegate to call after the callback completion }
/// </param>
/// <param name="workItemPriority">The work item priority</param> [MethodImpl(MethodImplOptions.NoInlining)]
/// <returns>Returns a work item result</returns> private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
public IWorkItemResult QueueWorkItem( {
WorkItemCallback callback, if(null == onIdle)
object state, {
PostExecuteWorkItemCallback postExecuteWorkItemCallback, return;
WorkItemPriority workItemPriority) }
{
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); Delegate[] delegates = onIdle.GetInvocationList();
EnqueueToSTPNextWorkItem(workItem); foreach(WorkItemsGroupIdleHandler eh in delegates)
return workItem.GetWorkItemResult(); {
} try
{
/// <summary> eh(this);
/// Queue a work item }
/// </summary> catch { } // Suppress exceptions
/// <param name="callback">A callback to execute</param> }
/// <param name="state"> }
/// The context object of the work item. Used for passing arguments to the work item.
/// </param> private void OnWorkItemStartedCallback(WorkItem workItem)
/// <param name="postExecuteWorkItemCallback"> {
/// A delegate to call after the callback completion lock(_lock)
/// </param> {
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> ++_workItemsExecutingInStp;
/// <returns>Returns a work item result</returns> }
public IWorkItemResult QueueWorkItem( }
WorkItemCallback callback,
object state, private void OnWorkItemCompletedCallback(WorkItem workItem)
PostExecuteWorkItemCallback postExecuteWorkItemCallback, {
CallToPostExecute callToPostExecute) EnqueueToSTPNextWorkItem(null, true);
{ }
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
EnqueueToSTPNextWorkItem(workItem); internal override void Enqueue(WorkItem workItem)
return workItem.GetWorkItemResult(); {
} EnqueueToSTPNextWorkItem(workItem);
}
/// <summary>
/// Queue a work item private void EnqueueToSTPNextWorkItem(WorkItem workItem)
/// </summary> {
/// <param name="callback">A callback to execute</param> EnqueueToSTPNextWorkItem(workItem, false);
/// <param name="state"> }
/// The context object of the work item. Used for passing arguments to the work item.
/// </param> private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue)
/// <param name="postExecuteWorkItemCallback"> {
/// A delegate to call after the callback completion lock(_lock)
/// </param> {
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param> // Got here from OnWorkItemCompletedCallback()
/// <param name="workItemPriority">The work item priority</param> if (decrementWorkItemsInStpQueue)
/// <returns>Returns a work item result</returns> {
public IWorkItemResult QueueWorkItem( --_workItemsInStpQueue;
WorkItemCallback callback,
object state, if(_workItemsInStpQueue < 0)
PostExecuteWorkItemCallback postExecuteWorkItemCallback, {
CallToPostExecute callToPostExecute, _workItemsInStpQueue = 0;
WorkItemPriority workItemPriority) }
{
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); --_workItemsExecutingInStp;
EnqueueToSTPNextWorkItem(workItem);
return workItem.GetWorkItemResult(); if(_workItemsExecutingInStp < 0)
} {
_workItemsExecutingInStp = 0;
/// <summary> }
/// Wait for the thread pool to be idle }
/// </summary>
public void WaitForIdle() // If the work item is not null then enqueue it
{ if (null != workItem)
WaitForIdle(Timeout.Infinite); {
} workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup;
/// <summary> RegisterToWorkItemCompletion(workItem.GetWorkItemResult());
/// Wait for the thread pool to be idle _workItemsQueue.Enqueue(workItem);
/// </summary> //_stp.IncrementWorkItemsCount();
public bool WaitForIdle(TimeSpan timeout)
{ if ((1 == _workItemsQueue.Count) &&
return WaitForIdle((int)timeout.TotalMilliseconds); (0 == _workItemsInStpQueue))
} {
_stp.RegisterWorkItemsGroup(this);
/// <summary> IsIdle = false;
/// Wait for the thread pool to be idle _isIdleWaitHandle.Reset();
/// </summary> }
public bool WaitForIdle(int millisecondsTimeout) }
{
_stp.ValidateWorkItemsGroupWaitForIdle(this); // If the work items queue of the group is empty than quit
return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false); if (0 == _workItemsQueue.Count)
} {
if (0 == _workItemsInStpQueue)
public int WaitingCallbacks {
{ _stp.UnregisterWorkItemsGroup(this);
get IsIdle = true;
{ _isIdleWaitHandle.Set();
return _workItemsQueue.Count; if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0)
} {
} _stp.QueueWorkItem(new WorkItemCallback(FireOnIdle));
}
public event WorkItemsGroupIdleHandler OnIdle }
{ return;
add }
{
_onIdle += value; if (!_isSuspended)
} {
remove if (_workItemsInStpQueue < _concurrency)
{ {
_onIdle -= value; WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
} try
} {
_stp.Enqueue(nextWorkItem);
public void Cancel() }
{ catch (ObjectDisposedException e)
lock(_lock) {
{ e.GetHashCode();
_canceledWorkItemsGroup.IsCanceled = true; // The STP has been shutdown
_workItemsQueue.Clear(); }
_workItemsInStpQueue = 0;
_canceledWorkItemsGroup = new CanceledWorkItemsGroup(); ++_workItemsInStpQueue;
} }
} }
}
public void Start() }
{
lock (this) #endregion
{ }
if (!_workItemsGroupStartInfo.StartSuspended)
{ #endregion
return; }
}
_workItemsGroupStartInfo.StartSuspended = false;
}
for(int i = 0; i < _concurrency; ++i)
{
EnqueueToSTPNextWorkItem(null, false);
}
}
#endregion
#region Private methods
private void RegisterToWorkItemCompletion(IWorkItemResult wir)
{
IInternalWorkItemResult iwir = wir as IInternalWorkItemResult;
iwir.OnWorkItemStarted += new WorkItemStateCallback(OnWorkItemStartedCallback);
iwir.OnWorkItemCompleted += new WorkItemStateCallback(OnWorkItemCompletedCallback);
}
public void OnSTPIsStarting()
{
lock (this)
{
if (_workItemsGroupStartInfo.StartSuspended)
{
return;
}
}
for(int i = 0; i < _concurrency; ++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);
}
// Ignore exceptions
catch{}
}
}
private void OnWorkItemStartedCallback(WorkItem workItem)
{
lock(_lock)
{
++_workItemsExecutingInStp;
}
}
private void OnWorkItemCompletedCallback(WorkItem workItem)
{
EnqueueToSTPNextWorkItem(null, true);
}
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);
Trace.WriteLine("WorkItemsGroup " + Name + " is NOT idle");
_isIdleWaitHandle.Reset();
}
}
// If the work items queue of the group is empty than quit
if (0 == _workItemsQueue.Count)
{
if (0 == _workItemsInStpQueue)
{
_stp.UnregisterWorkItemsGroup(this);
Trace.WriteLine("WorkItemsGroup " + Name + " is idle");
_isIdleWaitHandle.Set();
_stp.QueueWorkItem(new WorkItemCallback(this.FireOnIdle));
}
return;
}
if (!_workItemsGroupStartInfo.StartSuspended)
{
if (_workItemsInStpQueue < _concurrency)
{
WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
_stp.Enqueue(nextWorkItem, true);
++_workItemsInStpQueue;
}
}
}
}
#endregion
}
#endregion
}

View File

@ -0,0 +1,471 @@
using System;
using System.Threading;
namespace Amib.Threading.Internal
{
public abstract class WorkItemsGroupBase : IWorkItemsGroup
{
#region Private Fields
/// <summary>
/// Contains the name of this instance of SmartThreadPool.
/// Can be changed by the user.
/// </summary>
private string _name = "WorkItemsGroupBase";
public WorkItemsGroupBase()
{
IsIdle = true;
}
#endregion
#region IWorkItemsGroup Members
#region Public Methods
/// <summary>
/// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance
/// </summary>
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
/// <summary>
/// Cancel all the work items.
/// Same as Cancel(false)
/// </summary>
public virtual void Cancel()
{
Cancel(false);
}
/// <summary>
/// Wait for the SmartThreadPool/WorkItemsGroup to be idle
/// </summary>
public void WaitForIdle()
{
WaitForIdle(Timeout.Infinite);
}
/// <summary>
/// Wait for the SmartThreadPool/WorkItemsGroup to be idle
/// </summary>
public bool WaitForIdle(TimeSpan timeout)
{
return WaitForIdle((int)timeout.TotalMilliseconds);
}
/// <summary>
/// IsIdle is true when there are no work items running or queued.
/// </summary>
public bool IsIdle { get; protected set; }
#endregion
#region QueueWorkItem
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="callback">A callback to execute</param>
/// <returns>Returns a work item result</returns>
public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
{
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="callback">A callback to execute</param>
/// <param name="workItemPriority">The priority of the work item</param>
/// <returns>Returns a work item result</returns>
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="workItemInfo">Work item info</param>
/// <param name="callback">A callback to execute</param>
/// <returns>Returns a work item result</returns>
public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
/// The context object of the work item. Used for passing arguments to the work item.
/// </param>
/// <returns>Returns a work item result</returns>
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
{
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
/// The context object of the work item. Used for passing arguments to the work item.
/// </param>
/// <param name="workItemPriority">The work item priority</param>
/// <returns>Returns a work item result</returns>
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="workItemInfo">Work item information</param>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
/// The context object of the work item. Used for passing arguments to the work item.
/// </param>
/// <returns>Returns a work item result</returns>
public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
/// The context object of the work item. Used for passing arguments to the work item.
/// </param>
/// <param name="postExecuteWorkItemCallback">
/// A delegate to call after the callback completion
/// </param>
/// <returns>Returns a work item result</returns>
public IWorkItemResult QueueWorkItem(
WorkItemCallback callback,
object state,
PostExecuteWorkItemCallback postExecuteWorkItemCallback)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
/// The context object of the work item. Used for passing arguments to the work item.
/// </param>
/// <param name="postExecuteWorkItemCallback">
/// A delegate to call after the callback completion
/// </param>
/// <param name="workItemPriority">The work item priority</param>
/// <returns>Returns a work item result</returns>
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();
}
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
/// The context object of the work item. Used for passing arguments to the work item.
/// </param>
/// <param name="postExecuteWorkItemCallback">
/// A delegate to call after the callback completion
/// </param>
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
/// <returns>Returns a work item result</returns>
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();
}
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
/// The context object of the work item. Used for passing arguments to the work item.
/// </param>
/// <param name="postExecuteWorkItemCallback">
/// A delegate to call after the callback completion
/// </param>
/// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
/// <param name="workItemPriority">The work item priority</param>
/// <returns>Returns a work item result</returns>
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<T>(Action<T> action, T arg)
{
return QueueWorkItem<T> (action, arg, SmartThreadPool.DefaultWorkItemPriority);
}
public IWorkItemResult QueueWorkItem<T> (Action<T> 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<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2)
{
return QueueWorkItem<T1, T2> (action, arg1, arg2, SmartThreadPool.DefaultWorkItemPriority);
}
public IWorkItemResult QueueWorkItem<T1, T2> (Action<T1, T2> 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<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
{
return QueueWorkItem<T1, T2, T3> (action, arg1, arg2, arg3, SmartThreadPool.DefaultWorkItemPriority);
;
}
public IWorkItemResult QueueWorkItem<T1, T2, T3> (Action<T1, T2, T3> 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<T1, T2, T3, T4>(
Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
return QueueWorkItem<T1, T2, T3, T4> (action, arg1, arg2, arg3, arg4,
SmartThreadPool.DefaultWorkItemPriority);
}
public IWorkItemResult QueueWorkItem<T1, T2, T3, T4> (
Action<T1, T2, T3, T4> 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<TResult> QueueWorkItem<TResult>(Func<TResult> func)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
state =>
{
return func.Invoke();
});
Enqueue(workItem);
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
}
public IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> 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<TResult>(workItem.GetWorkItemResult());
}
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> 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<TResult>(workItem.GetWorkItemResult());
}
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(
Func<T1, T2, T3, TResult> 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<TResult>(workItem.GetWorkItemResult());
}
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(
Func<T1, T2, T3, T4, TResult> 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<TResult>(workItem.GetWorkItemResult());
}
#endregion
#endregion
}
}

File diff suppressed because it is too large Load Diff