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=6586user_profiles
parent
ac135c649c
commit
206fb306a7
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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("")]
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
@ -6,7 +9,7 @@ using System.Web;
|
||||||
using System.Runtime.Remoting.Messaging;
|
using System.Runtime.Remoting.Messaging;
|
||||||
|
|
||||||
|
|
||||||
namespace Amib.Threading
|
namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
#region CallerThreadContext class
|
#region CallerThreadContext class
|
||||||
|
|
||||||
|
@ -19,10 +22,10 @@ namespace Amib.Threading
|
||||||
#region Prepare reflection information
|
#region Prepare reflection information
|
||||||
|
|
||||||
// Cached type information.
|
// Cached type information.
|
||||||
private static MethodInfo getLogicalCallContextMethodInfo =
|
private static readonly MethodInfo getLogicalCallContextMethodInfo =
|
||||||
typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
|
typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
private static MethodInfo setLogicalCallContextMethodInfo =
|
private static readonly MethodInfo setLogicalCallContextMethodInfo =
|
||||||
typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
|
typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
private static string HttpContextSlotName = GetHttpContextSlotName();
|
private static string HttpContextSlotName = GetHttpContextSlotName();
|
||||||
|
@ -32,8 +35,10 @@ namespace Amib.Threading
|
||||||
FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
|
FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
if (fi != null)
|
if (fi != null)
|
||||||
|
{
|
||||||
return (string) fi.GetValue(null);
|
return (string) fi.GetValue(null);
|
||||||
else // Use the default "HttpContext" slot name
|
}
|
||||||
|
|
||||||
return "HttpContext";
|
return "HttpContext";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,8 +46,8 @@ namespace Amib.Threading
|
||||||
|
|
||||||
#region Private fields
|
#region Private fields
|
||||||
|
|
||||||
private HttpContext _httpContext = null;
|
private HttpContext _httpContext;
|
||||||
private LogicalCallContext _callContext = null;
|
private LogicalCallContext _callContext;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -122,102 +127,12 @@ namespace Amib.Threading
|
||||||
// Restore HttpContext
|
// Restore HttpContext
|
||||||
if (callerThreadContext._httpContext != null)
|
if (callerThreadContext._httpContext != null)
|
||||||
{
|
{
|
||||||
CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
|
HttpContext.Current = callerThreadContext._httpContext;
|
||||||
|
//CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
// Ami Bar
|
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +1,82 @@
|
||||||
// Ami Bar
|
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
#if !(_WINDOWS_CE)
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Amib.Threading
|
namespace Amib.Threading
|
||||||
{
|
{
|
||||||
#region Exceptions
|
#region Exceptions
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class WorkItemCancelException : Exception
|
||||||
|
{
|
||||||
|
public WorkItemCancelException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemCancelException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemCancelException(string message, Exception e)
|
||||||
|
: base(message, e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class WorkItemTimeoutException : Exception
|
||||||
|
{
|
||||||
|
public WorkItemTimeoutException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemTimeoutException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemTimeoutException(string message, Exception e)
|
||||||
|
: base(message, e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class WorkItemResultException : Exception
|
||||||
|
{
|
||||||
|
public WorkItemResultException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemResultException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public WorkItemResultException(string message, Exception e)
|
||||||
|
: base(message, e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
|
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public sealed class WorkItemCancelException : ApplicationException
|
public sealed partial class WorkItemCancelException
|
||||||
{
|
{
|
||||||
public WorkItemCancelException() : base()
|
public WorkItemCancelException(SerializationInfo si, StreamingContext sc)
|
||||||
{
|
: base(si, sc)
|
||||||
}
|
|
||||||
|
|
||||||
public WorkItemCancelException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkItemCancelException(string message, Exception e) : base(message, e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkItemCancelException(SerializationInfo si, StreamingContext sc) : base(si, sc)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,21 +85,10 @@ namespace Amib.Threading
|
||||||
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public sealed class WorkItemTimeoutException : ApplicationException
|
public sealed partial class WorkItemTimeoutException
|
||||||
{
|
{
|
||||||
public WorkItemTimeoutException() : base()
|
public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc)
|
||||||
{
|
: base(si, sc)
|
||||||
}
|
|
||||||
|
|
||||||
public WorkItemTimeoutException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkItemTimeoutException(string message, Exception e) : base(message, e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) : base(si, sc)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,24 +97,15 @@ namespace Amib.Threading
|
||||||
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public sealed class WorkItemResultException : ApplicationException
|
public sealed partial class WorkItemResultException
|
||||||
{
|
{
|
||||||
public WorkItemResultException() : base()
|
public WorkItemResultException(SerializationInfo si, StreamingContext sc)
|
||||||
|
: base(si, sc)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public WorkItemResultException(string message) : base(message)
|
#endif
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkItemResultException(string message, Exception e) : base(message, e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkItemResultException(SerializationInfo si, StreamingContext sc) : base(si, sc)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
// Ami Bar
|
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
@ -20,16 +17,39 @@ namespace Amib.Threading
|
||||||
/// <param name="wir">The work item result object</param>
|
/// <param name="wir">The work item result object</param>
|
||||||
public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
|
public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A delegate to call after the WorkItemCallback completed
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="wir">The work item result object</param>
|
||||||
|
public delegate void PostExecuteWorkItemCallback<TResult>(IWorkItemResult<TResult> wir);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A delegate to call when a WorkItemsGroup becomes idle
|
/// A delegate to call when a WorkItemsGroup becomes idle
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param>
|
/// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param>
|
||||||
public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
|
public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A delegate to call after a thread is created, but before
|
||||||
|
/// it's first use.
|
||||||
|
/// </summary>
|
||||||
|
public delegate void ThreadInitializationHandler();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A delegate to call when a thread is about to exit, after
|
||||||
|
/// it is no longer belong to the pool.
|
||||||
|
/// </summary>
|
||||||
|
public delegate void ThreadTerminationHandler();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region WorkItem Priority
|
#region WorkItem Priority
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the availeable priorities of a work item.
|
||||||
|
/// The higher the priority a work item has, the sooner
|
||||||
|
/// it will be executed.
|
||||||
|
/// </summary>
|
||||||
public enum WorkItemPriority
|
public enum WorkItemPriority
|
||||||
{
|
{
|
||||||
Lowest,
|
Lowest,
|
||||||
|
@ -41,19 +61,11 @@ namespace Amib.Threading
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IHasWorkItemPriority interface
|
|
||||||
|
|
||||||
public interface IHasWorkItemPriority
|
|
||||||
{
|
|
||||||
WorkItemPriority WorkItemPriority { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IWorkItemsGroup interface
|
#region IWorkItemsGroup interface
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// IWorkItemsGroup interface
|
/// IWorkItemsGroup interface
|
||||||
|
/// Created by SmartThreadPool.CreateWorkItemsGroup()
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IWorkItemsGroup
|
public interface IWorkItemsGroup
|
||||||
{
|
{
|
||||||
|
@ -62,27 +74,293 @@ namespace Amib.Threading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Name { get; set; }
|
string Name { get; set; }
|
||||||
|
|
||||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback);
|
/// <summary>
|
||||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
|
/// Get/Set the maximum number of workitem that execute cocurrency on the thread pool
|
||||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
|
/// </summary>
|
||||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
|
int Concurrency { get; set; }
|
||||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
|
|
||||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
|
|
||||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
|
|
||||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
|
|
||||||
|
|
||||||
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
|
/// <summary>
|
||||||
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
|
/// Get the number of work items waiting in the queue.
|
||||||
|
/// </summary>
|
||||||
|
int WaitingCallbacks { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get an array with all the state objects of the currently running items.
|
||||||
|
/// The array represents a snap shot and impact performance.
|
||||||
|
/// </summary>
|
||||||
|
object[] GetStates();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the WorkItemsGroup start information
|
||||||
|
/// </summary>
|
||||||
|
WIGStartInfo WIGStartInfo { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts to execute work items
|
||||||
|
/// </summary>
|
||||||
|
void Start();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancel all the work items.
|
||||||
|
/// Same as Cancel(false)
|
||||||
|
/// </summary>
|
||||||
|
void Cancel();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancel all work items using thread abortion
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param>
|
||||||
|
void Cancel(bool abortExecution);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait for all work item to complete.
|
||||||
|
/// </summary>
|
||||||
void WaitForIdle();
|
void WaitForIdle();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait for all work item to complete, until timeout expired
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeout">How long to wait for the work items to complete</param>
|
||||||
|
/// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
|
||||||
bool WaitForIdle(TimeSpan timeout);
|
bool WaitForIdle(TimeSpan timeout);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wait for all work item to complete, until timeout expired
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="millisecondsTimeout">How long to wait for the work items to complete in milliseconds</param>
|
||||||
|
/// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
|
||||||
bool WaitForIdle(int millisecondsTimeout);
|
bool WaitForIdle(int millisecondsTimeout);
|
||||||
|
|
||||||
int WaitingCallbacks { get; }
|
/// <summary>
|
||||||
|
/// IsIdle is true when there are no work items running or queued.
|
||||||
|
/// </summary>
|
||||||
|
bool IsIdle { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This event is fired when all work items are completed.
|
||||||
|
/// (When IsIdle changes to true)
|
||||||
|
/// This event only work on WorkItemsGroup. On SmartThreadPool
|
||||||
|
/// it throws the NotImplementedException.
|
||||||
|
/// </summary>
|
||||||
event WorkItemsGroupIdleHandler OnIdle;
|
event WorkItemsGroupIdleHandler OnIdle;
|
||||||
|
|
||||||
void Cancel();
|
#region QueueWorkItem
|
||||||
void Start();
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
/// <returns>Returns a work item result</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback);
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region QueueWorkItem(Action<...>)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queue a work item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
|
||||||
|
IWorkItemResult QueueWorkItem(Action action);
|
||||||
|
|
||||||
|
/// <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<TResult> 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<TResult> 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<TResult> 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<TResult> 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<TResult> 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
|
#endregion
|
||||||
|
@ -92,9 +370,24 @@ namespace Amib.Threading
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum CallToPostExecute
|
public enum CallToPostExecute
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Never call to the PostExecute call back
|
||||||
|
/// </summary>
|
||||||
Never = 0x00,
|
Never = 0x00,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Call to the PostExecute only when the work item is cancelled
|
||||||
|
/// </summary>
|
||||||
WhenWorkItemCanceled = 0x01,
|
WhenWorkItemCanceled = 0x01,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Call to the PostExecute only when the work item is not cancelled
|
||||||
|
/// </summary>
|
||||||
WhenWorkItemNotCanceled = 0x02,
|
WhenWorkItemNotCanceled = 0x02,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Always call to the PostExecute
|
||||||
|
/// </summary>
|
||||||
Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
|
Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,16 +396,43 @@ namespace Amib.Threading
|
||||||
#region IWorkItemResult interface
|
#region IWorkItemResult interface
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// IWorkItemResult interface
|
/// The common interface of IWorkItemResult and IWorkItemResult<T>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IWorkItemResult
|
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<TResult> interface.
|
||||||
|
/// Created when a Func<TResult> work item is queued.
|
||||||
|
/// </summary>
|
||||||
|
public interface IWorkItemResult<TResult> : IWaitableResult
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the result of the work item.
|
/// Get the result of the work item.
|
||||||
/// If the work item didn't run yet then the caller waits.
|
/// If the work item didn't run yet then the caller waits.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The result of the work item</returns>
|
/// <returns>The result of the work item</returns>
|
||||||
object GetResult();
|
TResult GetResult();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the result of the work item.
|
/// Get the result of the work item.
|
||||||
|
@ -120,7 +440,7 @@ namespace Amib.Threading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The result of the work item</returns>
|
/// <returns>The result of the work item</returns>
|
||||||
/// On timeout throws WorkItemTimeoutException
|
/// On timeout throws WorkItemTimeoutException
|
||||||
object GetResult(
|
TResult GetResult(
|
||||||
int millisecondsTimeout,
|
int millisecondsTimeout,
|
||||||
bool exitContext);
|
bool exitContext);
|
||||||
|
|
||||||
|
@ -130,12 +450,10 @@ namespace Amib.Threading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The result of the work item</returns>
|
/// <returns>The result of the work item</returns>
|
||||||
/// On timeout throws WorkItemTimeoutException
|
/// On timeout throws WorkItemTimeoutException
|
||||||
object GetResult(
|
TResult GetResult(
|
||||||
TimeSpan timeout,
|
TimeSpan timeout,
|
||||||
bool exitContext);
|
bool exitContext);
|
||||||
|
|
||||||
void Abort();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the result of the work item.
|
/// 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.
|
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||||
|
@ -148,7 +466,7 @@ namespace Amib.Threading
|
||||||
/// <returns>The result of the work item</returns>
|
/// <returns>The result of the work item</returns>
|
||||||
/// On timeout throws WorkItemTimeoutException
|
/// On timeout throws WorkItemTimeoutException
|
||||||
/// On cancel throws WorkItemCancelException
|
/// On cancel throws WorkItemCancelException
|
||||||
object GetResult(
|
TResult GetResult(
|
||||||
int millisecondsTimeout,
|
int millisecondsTimeout,
|
||||||
bool exitContext,
|
bool exitContext,
|
||||||
WaitHandle cancelWaitHandle);
|
WaitHandle cancelWaitHandle);
|
||||||
|
@ -160,7 +478,7 @@ namespace Amib.Threading
|
||||||
/// <returns>The result of the work item</returns>
|
/// <returns>The result of the work item</returns>
|
||||||
/// On timeout throws WorkItemTimeoutException
|
/// On timeout throws WorkItemTimeoutException
|
||||||
/// On cancel throws WorkItemCancelException
|
/// On cancel throws WorkItemCancelException
|
||||||
object GetResult(
|
TResult GetResult(
|
||||||
TimeSpan timeout,
|
TimeSpan timeout,
|
||||||
bool exitContext,
|
bool exitContext,
|
||||||
WaitHandle cancelWaitHandle);
|
WaitHandle cancelWaitHandle);
|
||||||
|
@ -171,16 +489,18 @@ namespace Amib.Threading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||||
/// <returns>The result of the work item</returns>
|
/// <returns>The result of the work item</returns>
|
||||||
object GetResult(out Exception e);
|
TResult GetResult(out Exception e);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the result of the work item.
|
/// Get the result of the work item.
|
||||||
/// If the work item didn't run yet then the caller waits until timeout.
|
/// If the work item didn't run yet then the caller waits until timeout.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="millisecondsTimeout"></param>
|
||||||
|
/// <param name="exitContext"></param>
|
||||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||||
/// <returns>The result of the work item</returns>
|
/// <returns>The result of the work item</returns>
|
||||||
/// On timeout throws WorkItemTimeoutException
|
/// On timeout throws WorkItemTimeoutException
|
||||||
object GetResult(
|
TResult GetResult(
|
||||||
int millisecondsTimeout,
|
int millisecondsTimeout,
|
||||||
bool exitContext,
|
bool exitContext,
|
||||||
out Exception e);
|
out Exception e);
|
||||||
|
@ -189,10 +509,12 @@ namespace Amib.Threading
|
||||||
/// Get the result of the work item.
|
/// Get the result of the work item.
|
||||||
/// If the work item didn't run yet then the caller waits until timeout.
|
/// If the work item didn't run yet then the caller waits until timeout.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="exitContext"></param>
|
||||||
/// <param name="e">Filled with the exception if one was thrown</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>
|
/// <returns>The result of the work item</returns>
|
||||||
/// On timeout throws WorkItemTimeoutException
|
/// On timeout throws WorkItemTimeoutException
|
||||||
object GetResult(
|
TResult GetResult(
|
||||||
TimeSpan timeout,
|
TimeSpan timeout,
|
||||||
bool exitContext,
|
bool exitContext,
|
||||||
out Exception e);
|
out Exception e);
|
||||||
|
@ -210,7 +532,7 @@ namespace Amib.Threading
|
||||||
/// <returns>The result of the work item</returns>
|
/// <returns>The result of the work item</returns>
|
||||||
/// On timeout throws WorkItemTimeoutException
|
/// On timeout throws WorkItemTimeoutException
|
||||||
/// On cancel throws WorkItemCancelException
|
/// On cancel throws WorkItemCancelException
|
||||||
object GetResult(
|
TResult GetResult(
|
||||||
int millisecondsTimeout,
|
int millisecondsTimeout,
|
||||||
bool exitContext,
|
bool exitContext,
|
||||||
WaitHandle cancelWaitHandle,
|
WaitHandle cancelWaitHandle,
|
||||||
|
@ -221,10 +543,13 @@ namespace Amib.Threading
|
||||||
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The result of the work item</returns>
|
/// <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="e">Filled with the exception if one was thrown</param>
|
||||||
|
/// <param name="timeout"></param>
|
||||||
|
/// <param name="exitContext"></param>
|
||||||
/// On timeout throws WorkItemTimeoutException
|
/// On timeout throws WorkItemTimeoutException
|
||||||
/// On cancel throws WorkItemCancelException
|
/// On cancel throws WorkItemCancelException
|
||||||
object GetResult(
|
TResult GetResult(
|
||||||
TimeSpan timeout,
|
TimeSpan timeout,
|
||||||
bool exitContext,
|
bool exitContext,
|
||||||
WaitHandle cancelWaitHandle,
|
WaitHandle cancelWaitHandle,
|
||||||
|
@ -241,16 +566,30 @@ namespace Amib.Threading
|
||||||
bool IsCanceled { get; }
|
bool IsCanceled { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
|
/// Gets the user-defined object that contains context data
|
||||||
|
/// for the work item method.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
object State { get; }
|
object State { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancel the work item if it didn't start running yet.
|
/// Same as Cancel(false).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
|
|
||||||
bool Cancel();
|
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>
|
/// <summary>
|
||||||
/// Get the work item's priority
|
/// Get the work item's priority
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -259,7 +598,7 @@ namespace Amib.Threading
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Return the result, same as GetResult()
|
/// Return the result, same as GetResult()
|
||||||
/// </summary>
|
/// </summary>
|
||||||
object Result { get; }
|
TResult Result { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the exception if occured otherwise returns null.
|
/// Returns the exception if occured otherwise returns null.
|
||||||
|
@ -267,5 +606,23 @@ namespace Amib.Threading
|
||||||
object Exception { get; }
|
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
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
// Ami Bar
|
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Amib.Threading.Internal
|
namespace Amib.Threading.Internal
|
||||||
|
@ -25,17 +23,17 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Work items queues. There is one for each type of priority
|
/// Work items queues. There is one for each type of priority
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Queue [] _queues = new Queue[_queuesCount];
|
private readonly LinkedList<IHasWorkItemPriority>[] _queues = new LinkedList<IHasWorkItemPriority>[_queuesCount];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The total number of work items within the queues
|
/// The total number of work items within the queues
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private int _workItemsCount = 0;
|
private int _workItemsCount;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Use with IEnumerable interface
|
/// Use with IEnumerable interface
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private int _version = 0;
|
private int _version;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -45,7 +43,7 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
for(int i = 0; i < _queues.Length; ++i)
|
for(int i = 0; i < _queues.Length; ++i)
|
||||||
{
|
{
|
||||||
_queues[i] = new Queue();
|
_queues[i] = new LinkedList<IHasWorkItemPriority>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +63,7 @@ namespace Amib.Threading.Internal
|
||||||
Debug.Assert(queueIndex >= 0);
|
Debug.Assert(queueIndex >= 0);
|
||||||
Debug.Assert(queueIndex < _queuesCount);
|
Debug.Assert(queueIndex < _queuesCount);
|
||||||
|
|
||||||
_queues[queueIndex].Enqueue(workItem);
|
_queues[queueIndex].AddLast(workItem);
|
||||||
++_workItemsCount;
|
++_workItemsCount;
|
||||||
++_version;
|
++_version;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +80,8 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
int queueIndex = GetNextNonEmptyQueue(-1);
|
int queueIndex = GetNextNonEmptyQueue(-1);
|
||||||
Debug.Assert(queueIndex >= 0);
|
Debug.Assert(queueIndex >= 0);
|
||||||
workItem = _queues[queueIndex].Dequeue() as IHasWorkItemPriority;
|
workItem = _queues[queueIndex].First.Value;
|
||||||
|
_queues[queueIndex].RemoveFirst();
|
||||||
Debug.Assert(null != workItem);
|
Debug.Assert(null != workItem);
|
||||||
--_workItemsCount;
|
--_workItemsCount;
|
||||||
++_version;
|
++_version;
|
||||||
|
@ -128,7 +127,7 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
if (_workItemsCount > 0)
|
if (_workItemsCount > 0)
|
||||||
{
|
{
|
||||||
foreach(Queue queue in _queues)
|
foreach(LinkedList<IHasWorkItemPriority> queue in _queues)
|
||||||
{
|
{
|
||||||
queue.Clear();
|
queue.Clear();
|
||||||
}
|
}
|
||||||
|
@ -159,7 +158,7 @@ namespace Amib.Threading.Internal
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private class PriorityQueueEnumerator : IEnumerator
|
private class PriorityQueueEnumerator : IEnumerator
|
||||||
{
|
{
|
||||||
private PriorityQueue _priorityQueue;
|
private readonly PriorityQueue _priorityQueue;
|
||||||
private int _version;
|
private int _version;
|
||||||
private int _queueIndex;
|
private int _queueIndex;
|
||||||
private IEnumerator _enumerator;
|
private IEnumerator _enumerator;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#if _SILVERLIGHT
|
||||||
|
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading
|
||||||
|
{
|
||||||
|
public enum ThreadPriority
|
||||||
|
{
|
||||||
|
Lowest,
|
||||||
|
BelowNormal,
|
||||||
|
Normal,
|
||||||
|
AboveNormal,
|
||||||
|
Highest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -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
|
|
@ -1,8 +1,30 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Amib.Threading
|
||||||
|
{
|
||||||
|
public interface ISTPPerformanceCountersReader
|
||||||
|
{
|
||||||
|
long InUseThreads { get; }
|
||||||
|
long ActiveThreads { get; }
|
||||||
|
long WorkItemsQueued { get; }
|
||||||
|
long WorkItemsProcessed { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace Amib.Threading.Internal
|
namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
|
internal interface ISTPInstancePerformanceCounters : IDisposable
|
||||||
|
{
|
||||||
|
void Close();
|
||||||
|
void SampleThreads(long activeThreads, long inUseThreads);
|
||||||
|
void SampleWorkItems(long workItemsQueued, long workItemsProcessed);
|
||||||
|
void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime);
|
||||||
|
void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime);
|
||||||
|
}
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
|
||||||
internal enum STPPerformanceCounterType
|
internal enum STPPerformanceCounterType
|
||||||
{
|
{
|
||||||
// Fields
|
// Fields
|
||||||
|
@ -37,7 +59,7 @@ namespace Amib.Threading.Internal
|
||||||
internal class STPPerformanceCounter
|
internal class STPPerformanceCounter
|
||||||
{
|
{
|
||||||
// Fields
|
// Fields
|
||||||
private PerformanceCounterType _pcType;
|
private readonly PerformanceCounterType _pcType;
|
||||||
protected string _counterHelp;
|
protected string _counterHelp;
|
||||||
protected string _counterName;
|
protected string _counterName;
|
||||||
|
|
||||||
|
@ -47,9 +69,9 @@ namespace Amib.Threading.Internal
|
||||||
string counterHelp,
|
string counterHelp,
|
||||||
PerformanceCounterType pcType)
|
PerformanceCounterType pcType)
|
||||||
{
|
{
|
||||||
this._counterName = counterName;
|
_counterName = counterName;
|
||||||
this._counterHelp = counterHelp;
|
_counterHelp = counterHelp;
|
||||||
this._pcType = pcType;
|
_pcType = pcType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCounterToCollection(CounterCreationDataCollection counterData)
|
public void AddCounterToCollection(CounterCreationDataCollection counterData)
|
||||||
|
@ -76,7 +98,7 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
// Fields
|
// Fields
|
||||||
internal STPPerformanceCounter[] _stpPerformanceCounters;
|
internal STPPerformanceCounter[] _stpPerformanceCounters;
|
||||||
private static STPPerformanceCounters _instance;
|
private static readonly STPPerformanceCounters _instance;
|
||||||
internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
|
internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
|
||||||
internal const string _stpCategoryName = "SmartThreadPool";
|
internal const string _stpCategoryName = "SmartThreadPool";
|
||||||
|
|
||||||
|
@ -127,19 +149,12 @@ namespace Amib.Threading.Internal
|
||||||
_stpPerformanceCounters[i].AddCounterToCollection(counters);
|
_stpPerformanceCounters[i].AddCounterToCollection(counters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// *********** Remark for .NET 2.0 ***********
|
|
||||||
// If you are here, it means you got the warning that this overload
|
|
||||||
// of the method is deprecated in .NET 2.0. To use the correct
|
|
||||||
// method overload, uncomment the third argument of
|
|
||||||
// the method.
|
|
||||||
#pragma warning disable 0618
|
|
||||||
PerformanceCounterCategory.Create(
|
PerformanceCounterCategory.Create(
|
||||||
_stpCategoryName,
|
_stpCategoryName,
|
||||||
_stpCategoryHelp,
|
_stpCategoryHelp,
|
||||||
//PerformanceCounterCategoryType.MultiInstance,
|
PerformanceCounterCategoryType.MultiInstance,
|
||||||
counters);
|
counters);
|
||||||
#pragma warning restore 0618
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,16 +171,18 @@ namespace Amib.Threading.Internal
|
||||||
internal class STPInstancePerformanceCounter : IDisposable
|
internal class STPInstancePerformanceCounter : IDisposable
|
||||||
{
|
{
|
||||||
// Fields
|
// Fields
|
||||||
|
private bool _isDisposed;
|
||||||
private PerformanceCounter _pcs;
|
private PerformanceCounter _pcs;
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
protected STPInstancePerformanceCounter()
|
protected STPInstancePerformanceCounter()
|
||||||
{
|
{
|
||||||
|
_isDisposed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public STPInstancePerformanceCounter(
|
public STPInstancePerformanceCounter(
|
||||||
string instance,
|
string instance,
|
||||||
STPPerformanceCounterType spcType)
|
STPPerformanceCounterType spcType) : this()
|
||||||
{
|
{
|
||||||
STPPerformanceCounters counters = STPPerformanceCounters.Instance;
|
STPPerformanceCounters counters = STPPerformanceCounters.Instance;
|
||||||
_pcs = new PerformanceCounter(
|
_pcs = new PerformanceCounter(
|
||||||
|
@ -176,10 +193,6 @@ namespace Amib.Threading.Internal
|
||||||
_pcs.RawValue = _pcs.RawValue;
|
_pcs.RawValue = _pcs.RawValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
~STPInstancePerformanceCounter()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
|
@ -192,9 +205,20 @@ namespace Amib.Threading.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
GC.SuppressFinalize(this);
|
}
|
||||||
|
}
|
||||||
|
_isDisposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Increment()
|
public virtual void Increment()
|
||||||
|
@ -216,27 +240,19 @@ namespace Amib.Threading.Internal
|
||||||
internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter
|
internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter
|
||||||
{
|
{
|
||||||
// Methods
|
// Methods
|
||||||
public STPInstanceNullPerformanceCounter() {}
|
|
||||||
public override void Increment() {}
|
public override void Increment() {}
|
||||||
public override void IncrementBy(long value) {}
|
public override void IncrementBy(long value) {}
|
||||||
public override void Set(long val) {}
|
public override void Set(long val) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface ISTPInstancePerformanceCounters : IDisposable
|
|
||||||
{
|
|
||||||
void Close();
|
|
||||||
void SampleThreads(long activeThreads, long inUseThreads);
|
|
||||||
void SampleWorkItems(long workItemsQueued, long workItemsProcessed);
|
|
||||||
void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime);
|
|
||||||
void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable
|
internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters
|
||||||
{
|
{
|
||||||
|
private bool _isDisposed;
|
||||||
// Fields
|
// Fields
|
||||||
private STPInstancePerformanceCounter[] _pcs;
|
private STPInstancePerformanceCounter[] _pcs;
|
||||||
private static STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
|
private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
static STPInstancePerformanceCounters()
|
static STPInstancePerformanceCounters()
|
||||||
|
@ -246,8 +262,13 @@ namespace Amib.Threading.Internal
|
||||||
|
|
||||||
public STPInstancePerformanceCounters(string instance)
|
public STPInstancePerformanceCounters(string instance)
|
||||||
{
|
{
|
||||||
|
_isDisposed = false;
|
||||||
_pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
|
_pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
|
||||||
// STPPerformanceCounters counters = STPPerformanceCounters.Instance;
|
|
||||||
|
// Call the STPPerformanceCounters.Instance so the static constructor will
|
||||||
|
// intialize the STPPerformanceCounters singleton.
|
||||||
|
STPPerformanceCounters.Instance.GetHashCode();
|
||||||
|
|
||||||
for (int i = 0; i < _pcs.Length; i++)
|
for (int i = 0; i < _pcs.Length; i++)
|
||||||
{
|
{
|
||||||
if (instance != null)
|
if (instance != null)
|
||||||
|
@ -272,22 +293,28 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
if (null != _pcs[i])
|
if (null != _pcs[i])
|
||||||
{
|
{
|
||||||
_pcs[i].Close();
|
_pcs[i].Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_pcs = null;
|
_pcs = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~STPInstancePerformanceCounters()
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void Dispose()
|
_isDisposed = true;
|
||||||
{
|
|
||||||
Close();
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
|
private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
|
||||||
|
@ -327,21 +354,17 @@ namespace Amib.Threading.Internal
|
||||||
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
|
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable
|
internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
|
||||||
{
|
{
|
||||||
static NullSTPInstancePerformanceCounters()
|
private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters();
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private static NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(null);
|
|
||||||
|
|
||||||
public static NullSTPInstancePerformanceCounters Instance
|
public static NullSTPInstancePerformanceCounters Instance
|
||||||
{
|
{
|
||||||
get { return _instance; }
|
get { return _instance; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public NullSTPInstancePerformanceCounters(string instance) {}
|
|
||||||
public void Close() {}
|
public void Close() {}
|
||||||
public void Dispose() {}
|
public void Dispose() {}
|
||||||
|
|
||||||
|
@ -349,6 +372,77 @@ namespace Amib.Threading.Internal
|
||||||
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
|
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
|
||||||
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
|
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
|
||||||
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {}
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
// Ami Bar
|
using System;
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Amib.Threading
|
namespace Amib.Threading
|
||||||
|
@ -10,104 +8,205 @@ namespace Amib.Threading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class STPStartInfo : WIGStartInfo
|
public class STPStartInfo : WIGStartInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
|
||||||
/// Idle timeout in milliseconds.
|
private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
|
||||||
/// If a thread is idle for _idleTimeout milliseconds then
|
private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
|
||||||
/// it may quit.
|
#if !(WINDOWS_PHONE)
|
||||||
/// </summary>
|
private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority;
|
||||||
private int _idleTimeout;
|
#endif
|
||||||
|
private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
|
||||||
|
private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground;
|
||||||
|
private bool _enableLocalPerformanceCounters;
|
||||||
|
private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName;
|
||||||
|
private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize;
|
||||||
|
|
||||||
/// <summary>
|
public STPStartInfo()
|
||||||
/// The lower limit of threads in the pool.
|
|
||||||
/// </summary>
|
|
||||||
private int _minWorkerThreads;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The upper limit of threads in the pool.
|
|
||||||
/// </summary>
|
|
||||||
private int _maxWorkerThreads;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The priority of the threads in the pool
|
|
||||||
/// </summary>
|
|
||||||
private ThreadPriority _threadPriority;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The thread pool name. Threads will get names depending on this.
|
|
||||||
/// </summary>
|
|
||||||
private string _threadPoolName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If this field is not null then the performance counters are enabled
|
|
||||||
/// and use the string as the name of the instance.
|
|
||||||
/// </summary>
|
|
||||||
private string _pcInstanceName;
|
|
||||||
|
|
||||||
private int _stackSize;
|
|
||||||
|
|
||||||
public STPStartInfo() : base()
|
|
||||||
{
|
{
|
||||||
|
_performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
|
||||||
|
#if !(WINDOWS_PHONE)
|
||||||
|
_threadPriority = SmartThreadPool.DefaultThreadPriority;
|
||||||
|
#endif
|
||||||
|
_maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
|
||||||
_idleTimeout = SmartThreadPool.DefaultIdleTimeout;
|
_idleTimeout = SmartThreadPool.DefaultIdleTimeout;
|
||||||
_minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
|
_minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
|
||||||
_maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
|
|
||||||
_threadPriority = SmartThreadPool.DefaultThreadPriority;
|
|
||||||
_threadPoolName = SmartThreadPool.DefaultThreadPoolName;
|
|
||||||
_pcInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
|
|
||||||
_stackSize = SmartThreadPool.DefaultStackSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public STPStartInfo(STPStartInfo stpStartInfo) : base(stpStartInfo)
|
public STPStartInfo(STPStartInfo stpStartInfo)
|
||||||
|
: base(stpStartInfo)
|
||||||
{
|
{
|
||||||
_idleTimeout = stpStartInfo._idleTimeout;
|
_idleTimeout = stpStartInfo.IdleTimeout;
|
||||||
_minWorkerThreads = stpStartInfo._minWorkerThreads;
|
_minWorkerThreads = stpStartInfo.MinWorkerThreads;
|
||||||
_maxWorkerThreads = stpStartInfo._maxWorkerThreads;
|
_maxWorkerThreads = stpStartInfo.MaxWorkerThreads;
|
||||||
_threadPriority = stpStartInfo._threadPriority;
|
#if !(WINDOWS_PHONE)
|
||||||
|
_threadPriority = stpStartInfo.ThreadPriority;
|
||||||
|
#endif
|
||||||
|
_performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName;
|
||||||
|
_enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters;
|
||||||
_threadPoolName = stpStartInfo._threadPoolName;
|
_threadPoolName = stpStartInfo._threadPoolName;
|
||||||
_pcInstanceName = stpStartInfo._pcInstanceName;
|
_areThreadsBackground = stpStartInfo.AreThreadsBackground;
|
||||||
_stackSize = stpStartInfo._stackSize;
|
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
_apartmentState = stpStartInfo._apartmentState;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public int IdleTimeout
|
/// <summary>
|
||||||
|
/// Get/Set the idle timeout in milliseconds.
|
||||||
|
/// If a thread is idle (starved) longer than IdleTimeout then it may quit.
|
||||||
|
/// </summary>
|
||||||
|
public virtual int IdleTimeout
|
||||||
{
|
{
|
||||||
get { return _idleTimeout; }
|
get { return _idleTimeout; }
|
||||||
set { _idleTimeout = value; }
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_idleTimeout = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int MinWorkerThreads
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the lower limit of threads in the pool.
|
||||||
|
/// </summary>
|
||||||
|
public virtual int MinWorkerThreads
|
||||||
{
|
{
|
||||||
get { return _minWorkerThreads; }
|
get { return _minWorkerThreads; }
|
||||||
set { _minWorkerThreads = value; }
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_minWorkerThreads = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int MaxWorkerThreads
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the upper limit of threads in the pool.
|
||||||
|
/// </summary>
|
||||||
|
public virtual int MaxWorkerThreads
|
||||||
{
|
{
|
||||||
get { return _maxWorkerThreads; }
|
get { return _maxWorkerThreads; }
|
||||||
set { _maxWorkerThreads = value; }
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_maxWorkerThreads = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThreadPriority ThreadPriority
|
#if !(WINDOWS_PHONE)
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the scheduling priority of the threads in the pool.
|
||||||
|
/// The Os handles the scheduling.
|
||||||
|
/// </summary>
|
||||||
|
public virtual ThreadPriority ThreadPriority
|
||||||
{
|
{
|
||||||
get { return _threadPriority; }
|
get { return _threadPriority; }
|
||||||
set { _threadPriority = value; }
|
set
|
||||||
}
|
|
||||||
|
|
||||||
public virtual string ThreadPoolName
|
|
||||||
{
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_threadPriority = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the thread pool name. Threads will get names depending on this.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ThreadPoolName {
|
||||||
get { return _threadPoolName; }
|
get { return _threadPoolName; }
|
||||||
set { _threadPoolName = value; }
|
set
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public string PerformanceCounterInstanceName
|
|
||||||
{
|
{
|
||||||
get { return _pcInstanceName; }
|
ThrowIfReadOnly ();
|
||||||
set { _pcInstanceName = value; }
|
_threadPoolName = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int StackSize
|
/// <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 _stackSize; }
|
get { return _performanceCounterInstanceName; }
|
||||||
set { _stackSize = value; }
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
// Ami Bar
|
using System;
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
namespace Amib.Threading
|
namespace Amib.Threading
|
||||||
{
|
{
|
||||||
|
@ -8,92 +7,165 @@ namespace Amib.Threading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WIGStartInfo
|
public class WIGStartInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Use the caller's security context
|
|
||||||
/// </summary>
|
|
||||||
private bool _useCallerCallContext;
|
private bool _useCallerCallContext;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Use the caller's HTTP context
|
|
||||||
/// </summary>
|
|
||||||
private bool _useCallerHttpContext;
|
private bool _useCallerHttpContext;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dispose of the state object of a work item
|
|
||||||
/// </summary>
|
|
||||||
private bool _disposeOfStateObjects;
|
private bool _disposeOfStateObjects;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The option to run the post execute
|
|
||||||
/// </summary>
|
|
||||||
private CallToPostExecute _callToPostExecute;
|
private CallToPostExecute _callToPostExecute;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A post execute callback to call when none is provided in
|
|
||||||
/// the QueueWorkItem method.
|
|
||||||
/// </summary>
|
|
||||||
private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
|
private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicate the WorkItemsGroup to suspend the handling of the work items
|
|
||||||
/// until the Start() method is called.
|
|
||||||
/// </summary>
|
|
||||||
private bool _startSuspended;
|
private bool _startSuspended;
|
||||||
|
private WorkItemPriority _workItemPriority;
|
||||||
|
private bool _fillStateWithArgs;
|
||||||
|
|
||||||
|
protected bool _readOnly;
|
||||||
|
|
||||||
public WIGStartInfo()
|
public WIGStartInfo()
|
||||||
{
|
{
|
||||||
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
_fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs;
|
||||||
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
_workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
|
||||||
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
|
||||||
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
|
||||||
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
|
||||||
_startSuspended = SmartThreadPool.DefaultStartSuspended;
|
_startSuspended = SmartThreadPool.DefaultStartSuspended;
|
||||||
|
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
||||||
|
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
||||||
|
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
||||||
|
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
||||||
|
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WIGStartInfo(WIGStartInfo wigStartInfo)
|
public WIGStartInfo(WIGStartInfo wigStartInfo)
|
||||||
{
|
{
|
||||||
_useCallerCallContext = wigStartInfo._useCallerCallContext;
|
_useCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||||
_useCallerHttpContext = wigStartInfo._useCallerHttpContext;
|
_useCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||||
_disposeOfStateObjects = wigStartInfo._disposeOfStateObjects;
|
_disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
_callToPostExecute = wigStartInfo._callToPostExecute;
|
_callToPostExecute = wigStartInfo.CallToPostExecute;
|
||||||
_postExecuteWorkItemCallback = wigStartInfo._postExecuteWorkItemCallback;
|
_postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
||||||
_startSuspended = wigStartInfo._startSuspended;
|
_workItemPriority = wigStartInfo.WorkItemPriority;
|
||||||
|
_startSuspended = wigStartInfo.StartSuspended;
|
||||||
|
_fillStateWithArgs = wigStartInfo.FillStateWithArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UseCallerCallContext
|
protected void ThrowIfReadOnly()
|
||||||
|
{
|
||||||
|
if (_readOnly)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("This is a readonly instance and set is not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set if to use the caller's security context
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool UseCallerCallContext
|
||||||
{
|
{
|
||||||
get { return _useCallerCallContext; }
|
get { return _useCallerCallContext; }
|
||||||
set { _useCallerCallContext = value; }
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_useCallerCallContext = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UseCallerHttpContext
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set if to use the caller's HTTP context
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool UseCallerHttpContext
|
||||||
{
|
{
|
||||||
get { return _useCallerHttpContext; }
|
get { return _useCallerHttpContext; }
|
||||||
set { _useCallerHttpContext = value; }
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_useCallerHttpContext = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DisposeOfStateObjects
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set if to dispose of the state object of a work item
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool DisposeOfStateObjects
|
||||||
{
|
{
|
||||||
get { return _disposeOfStateObjects; }
|
get { return _disposeOfStateObjects; }
|
||||||
set { _disposeOfStateObjects = value; }
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_disposeOfStateObjects = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CallToPostExecute CallToPostExecute
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the run the post execute options
|
||||||
|
/// </summary>
|
||||||
|
public virtual CallToPostExecute CallToPostExecute
|
||||||
{
|
{
|
||||||
get { return _callToPostExecute; }
|
get { return _callToPostExecute; }
|
||||||
set { _callToPostExecute = value; }
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_callToPostExecute = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the default post execute callback
|
||||||
|
/// </summary>
|
||||||
|
public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback
|
||||||
{
|
{
|
||||||
get { return _postExecuteWorkItemCallback; }
|
get { return _postExecuteWorkItemCallback; }
|
||||||
set { _postExecuteWorkItemCallback = value; }
|
set
|
||||||
|
{
|
||||||
|
ThrowIfReadOnly();
|
||||||
|
_postExecuteWorkItemCallback = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool StartSuspended
|
|
||||||
|
/// <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; }
|
get { return _startSuspended; }
|
||||||
set { _startSuspended = value; }
|
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<...>/Func<...> 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 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,58 +1,13 @@
|
||||||
// Ami Bar
|
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Amib.Threading.Internal
|
namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
#region WorkItem Delegate
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An internal delegate to call when the WorkItem starts or completes
|
|
||||||
/// </summary>
|
|
||||||
internal delegate void WorkItemStateCallback(WorkItem workItem);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IInternalWorkItemResult interface
|
|
||||||
|
|
||||||
public class CanceledWorkItemsGroup
|
|
||||||
{
|
|
||||||
public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
|
||||||
|
|
||||||
private bool _isCanceled = false;
|
|
||||||
public bool IsCanceled
|
|
||||||
{
|
|
||||||
get { return _isCanceled; }
|
|
||||||
set { _isCanceled = value; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal interface IInternalWorkItemResult
|
|
||||||
{
|
|
||||||
event WorkItemStateCallback OnWorkItemStarted;
|
|
||||||
event WorkItemStateCallback OnWorkItemCompleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IWorkItem interface
|
|
||||||
|
|
||||||
public interface IWorkItem
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region WorkItem class
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Holds a callback delegate and the state for that delegate.
|
/// Holds a callback delegate and the state for that delegate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WorkItem : IHasWorkItemPriority, IWorkItem
|
public partial class WorkItem : IHasWorkItemPriority
|
||||||
{
|
{
|
||||||
#region WorkItemState enum
|
#region WorkItemState enum
|
||||||
|
|
||||||
|
@ -61,33 +16,57 @@ namespace Amib.Threading.Internal
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private enum WorkItemState
|
private enum WorkItemState
|
||||||
{
|
{
|
||||||
InQueue,
|
InQueue = 0, // Nexts: InProgress, Canceled
|
||||||
InProgress,
|
InProgress = 1, // Nexts: Completed, Canceled
|
||||||
Completed,
|
Completed = 2, // Stays Completed
|
||||||
Canceled,
|
Canceled = 3, // Stays Canceled
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsValidStatesTransition(WorkItemState currentState, WorkItemState nextState)
|
||||||
|
{
|
||||||
|
bool valid = false;
|
||||||
|
|
||||||
|
switch (currentState)
|
||||||
|
{
|
||||||
|
case WorkItemState.InQueue:
|
||||||
|
valid = (WorkItemState.InProgress == nextState) || (WorkItemState.Canceled == nextState);
|
||||||
|
break;
|
||||||
|
case WorkItemState.InProgress:
|
||||||
|
valid = (WorkItemState.Completed == nextState) || (WorkItemState.Canceled == nextState);
|
||||||
|
break;
|
||||||
|
case WorkItemState.Completed:
|
||||||
|
case WorkItemState.Canceled:
|
||||||
|
// Cannot be changed
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Unknown state
|
||||||
|
Debug.Assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Member Variables
|
#region Fields
|
||||||
|
|
||||||
public Thread currentThread;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Callback delegate for the callback.
|
/// Callback delegate for the callback.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private WorkItemCallback _callback;
|
private readonly WorkItemCallback _callback;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// State with which to call the callback delegate.
|
/// State with which to call the callback delegate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _state;
|
private object _state;
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores the caller's context
|
/// Stores the caller's context
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private CallerThreadContext _callerContext;
|
private readonly CallerThreadContext _callerContext;
|
||||||
|
#endif
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Holds the result of the mehtod
|
/// Holds the result of the mehtod
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -117,12 +96,12 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the result state of the work item
|
/// Represents the result state of the work item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private WorkItemResult _workItemResult;
|
private readonly WorkItemResult _workItemResult;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Work item info
|
/// Work item info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private WorkItemInfo _workItemInfo;
|
private readonly WorkItemInfo _workItemInfo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when the WorkItem starts
|
/// Called when the WorkItem starts
|
||||||
|
@ -141,30 +120,41 @@ namespace Amib.Threading.Internal
|
||||||
private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
|
private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The work item group this work item belong to.
|
/// A reference to an object that indicates whatever the
|
||||||
///
|
/// SmartThreadPool has been canceled
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private IWorkItemsGroup _workItemsGroup;
|
private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The work item group this work item belong to.
|
||||||
|
/// </summary>
|
||||||
|
private readonly IWorkItemsGroup _workItemsGroup;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The thread that executes this workitem.
|
||||||
|
/// This field is available for the period when the work item is executed, before and after it is null.
|
||||||
|
/// </summary>
|
||||||
|
private Thread _executingThread;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The absulote time when the work item will be timeout
|
||||||
|
/// </summary>
|
||||||
|
private long _expirationTime;
|
||||||
|
|
||||||
#region Performance Counter fields
|
#region Performance Counter fields
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The time when the work items is queued.
|
|
||||||
/// Used with the performance counter.
|
|
||||||
/// </summary>
|
|
||||||
private DateTime _queuedTime;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time when the work items starts its execution.
|
/// Stores how long the work item waited on the stp queue
|
||||||
/// Used with the performance counter.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private DateTime _beginProcessTime;
|
private Stopwatch _waitingOnQueueStopwatch;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time when the work items ends its execution.
|
/// Stores how much time it took the work item to execute after it went out of the queue
|
||||||
/// Used with the performance counter.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private DateTime _endProcessTime;
|
private Stopwatch _processingStopwatch;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -176,7 +166,7 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (_beginProcessTime - _queuedTime);
|
return _waitingOnQueueStopwatch.Elapsed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +174,15 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (_endProcessTime - _beginProcessTime);
|
return _processingStopwatch.Elapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal WorkItemInfo WorkItemInfo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _workItemInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,6 +193,8 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize the callback holding object.
|
/// Initialize the callback holding object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The workItemGroup of the workitem</param>
|
||||||
|
/// <param name="workItemInfo">The WorkItemInfo of te workitem</param>
|
||||||
/// <param name="callback">Callback delegate for the callback.</param>
|
/// <param name="callback">Callback delegate for the callback.</param>
|
||||||
/// <param name="state">State with which to call the callback delegate.</param>
|
/// <param name="state">State with which to call the callback delegate.</param>
|
||||||
///
|
///
|
||||||
|
@ -209,10 +209,12 @@ namespace Amib.Threading.Internal
|
||||||
_workItemsGroup = workItemsGroup;
|
_workItemsGroup = workItemsGroup;
|
||||||
_workItemInfo = workItemInfo;
|
_workItemInfo = workItemInfo;
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext)
|
if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext)
|
||||||
{
|
{
|
||||||
_callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext);
|
_callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
_state = state;
|
_state = state;
|
||||||
|
@ -222,9 +224,18 @@ namespace Amib.Threading.Internal
|
||||||
|
|
||||||
internal void Initialize()
|
internal void Initialize()
|
||||||
{
|
{
|
||||||
|
// The _workItemState is changed directly instead of using the SetWorkItemState
|
||||||
|
// method since we don't want to go throught IsValidStateTransition.
|
||||||
_workItemState = WorkItemState.InQueue;
|
_workItemState = WorkItemState.InQueue;
|
||||||
|
|
||||||
_workItemCompleted = null;
|
_workItemCompleted = null;
|
||||||
_workItemCompletedRefCount = 0;
|
_workItemCompletedRefCount = 0;
|
||||||
|
_waitingOnQueueStopwatch = new Stopwatch();
|
||||||
|
_processingStopwatch = new Stopwatch();
|
||||||
|
_expirationTime =
|
||||||
|
_workItemInfo.Timeout > 0 ?
|
||||||
|
DateTime.UtcNow.Ticks + _workItemInfo.Timeout * TimeSpan.TicksPerMillisecond :
|
||||||
|
long.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup)
|
internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup)
|
||||||
|
@ -237,17 +248,16 @@ namespace Amib.Threading.Internal
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
public CanceledWorkItemsGroup CanceledWorkItemsGroup
|
internal CanceledWorkItemsGroup CanceledWorkItemsGroup
|
||||||
{
|
{
|
||||||
get
|
get { return _canceledWorkItemsGroup; }
|
||||||
{
|
set { _canceledWorkItemsGroup = value; }
|
||||||
return _canceledWorkItemsGroup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set
|
internal CanceledWorkItemsGroup CanceledSmartThreadPool
|
||||||
{
|
{
|
||||||
_canceledWorkItemsGroup = value;
|
get { return _canceledSmartThreadPool; }
|
||||||
}
|
set { _canceledSmartThreadPool = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -259,7 +269,8 @@ namespace Amib.Threading.Internal
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public bool StartingWorkItem()
|
public bool StartingWorkItem()
|
||||||
{
|
{
|
||||||
_beginProcessTime = DateTime.Now;
|
_waitingOnQueueStopwatch.Stop();
|
||||||
|
_processingStopwatch.Start();
|
||||||
|
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
|
@ -277,6 +288,9 @@ namespace Amib.Threading.Internal
|
||||||
|
|
||||||
Debug.Assert(WorkItemState.InQueue == GetWorkItemState());
|
Debug.Assert(WorkItemState.InQueue == GetWorkItemState());
|
||||||
|
|
||||||
|
// No need for a lock yet, only after the state has changed to InProgress
|
||||||
|
_executingThread = Thread.CurrentThread;
|
||||||
|
|
||||||
SetWorkItemState(WorkItemState.InProgress);
|
SetWorkItemState(WorkItemState.InProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +325,7 @@ namespace Amib.Threading.Internal
|
||||||
PostExecute();
|
PostExecute();
|
||||||
}
|
}
|
||||||
|
|
||||||
_endProcessTime = DateTime.Now;
|
_processingStopwatch.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void FireWorkItemCompleted()
|
internal void FireWorkItemCompleted()
|
||||||
|
@ -323,7 +337,20 @@ namespace Amib.Threading.Internal
|
||||||
_workItemCompletedEvent(this);
|
_workItemCompletedEvent(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch // Ignore exceptions
|
catch // Suppress exceptions
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void FireWorkItemStarted()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (null != _workItemStartedEvent)
|
||||||
|
{
|
||||||
|
_workItemStartedEvent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch // Suppress exceptions
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,16 +359,21 @@ namespace Amib.Threading.Internal
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void ExecuteWorkItem()
|
private void ExecuteWorkItem()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
CallerThreadContext ctc = null;
|
CallerThreadContext ctc = null;
|
||||||
if (null != _callerContext)
|
if (null != _callerContext)
|
||||||
{
|
{
|
||||||
ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext);
|
ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext);
|
||||||
CallerThreadContext.Apply(_callerContext);
|
CallerThreadContext.Apply(_callerContext);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Exception exception = null;
|
Exception exception = null;
|
||||||
object result = null;
|
object result = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = _callback(_state);
|
result = _callback(_state);
|
||||||
|
@ -352,13 +384,46 @@ namespace Amib.Threading.Internal
|
||||||
exception = e;
|
exception = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the value of the execution thread, so it will be impossible to cancel the work item,
|
||||||
|
// since it is already completed.
|
||||||
|
// Cancelling a work item that already completed may cause the abortion of the next work item!!!
|
||||||
|
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
|
||||||
|
|
||||||
|
if (null == executionThread)
|
||||||
|
{
|
||||||
|
// Oops! we are going to be aborted..., Wait here so we can catch the ThreadAbortException
|
||||||
|
Thread.Sleep(60 * 1000);
|
||||||
|
|
||||||
|
// If after 1 minute this thread was not aborted then let it continue working.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We must treat the ThreadAbortException or else it will be stored in the exception variable
|
||||||
|
catch (ThreadAbortException tae)
|
||||||
|
{
|
||||||
|
tae.GetHashCode();
|
||||||
|
// Check if the work item was cancelled
|
||||||
|
// If we got a ThreadAbortException and the STP is not shutting down, it means the
|
||||||
|
// work items was cancelled.
|
||||||
|
if (!SmartThreadPool.CurrentThreadEntry.AssociatedSmartThreadPool.IsShuttingdown)
|
||||||
|
{
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
Thread.ResetAbort();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
if (null != _callerContext)
|
if (null != _callerContext)
|
||||||
{
|
{
|
||||||
CallerThreadContext.Apply(ctc);
|
CallerThreadContext.Apply(ctc);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!SmartThreadPool.IsWorkItemCanceled)
|
||||||
|
{
|
||||||
SetResult(result, exception);
|
SetResult(result, exception);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs the post execute callback
|
/// Runs the post execute callback
|
||||||
|
@ -369,7 +434,7 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_workItemInfo.PostExecuteWorkItemCallback(this._workItemResult);
|
_workItemInfo.PostExecuteWorkItemCallback(_workItemResult);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -382,6 +447,8 @@ namespace Amib.Threading.Internal
|
||||||
/// Set the result of the work item to return
|
/// Set the result of the work item to return
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The result of the work item</param>
|
/// <param name="result">The result of the work item</param>
|
||||||
|
/// <param name="exception">The exception that was throw while the workitem executed, null
|
||||||
|
/// if there was no exception.</param>
|
||||||
internal void SetResult(object result, Exception exception)
|
internal void SetResult(object result, Exception exception)
|
||||||
{
|
{
|
||||||
_result = result;
|
_result = result;
|
||||||
|
@ -401,39 +468,39 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wait for all work items to complete
|
/// Wait for all work items to complete
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItemResults">Array of work item result objects</param>
|
/// <param name="waitableResults">Array of work item result objects</param>
|
||||||
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
|
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
|
||||||
/// <param name="exitContext">
|
/// <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.
|
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
|
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// true when every work item in workItemResults has completed; otherwise false.
|
/// true when every work item in waitableResults has completed; otherwise false.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
internal static bool WaitAll(
|
internal static bool WaitAll(
|
||||||
IWorkItemResult [] workItemResults,
|
IWaitableResult[] waitableResults,
|
||||||
int millisecondsTimeout,
|
int millisecondsTimeout,
|
||||||
bool exitContext,
|
bool exitContext,
|
||||||
WaitHandle cancelWaitHandle)
|
WaitHandle cancelWaitHandle)
|
||||||
{
|
{
|
||||||
if (0 == workItemResults.Length)
|
if (0 == waitableResults.Length)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success;
|
bool success;
|
||||||
WaitHandle [] waitHandles = new WaitHandle[workItemResults.Length];;
|
WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length];
|
||||||
GetWaitHandles(workItemResults, waitHandles);
|
GetWaitHandles(waitableResults, waitHandles);
|
||||||
|
|
||||||
if ((null == cancelWaitHandle) && (waitHandles.Length <= 64))
|
if ((null == cancelWaitHandle) && (waitHandles.Length <= 64))
|
||||||
{
|
{
|
||||||
success = WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
|
success = STPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
success = true;
|
success = true;
|
||||||
int millisecondsLeft = millisecondsTimeout;
|
int millisecondsLeft = millisecondsTimeout;
|
||||||
DateTime start = DateTime.Now;
|
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
WaitHandle[] whs;
|
WaitHandle[] whs;
|
||||||
if (null != cancelWaitHandle)
|
if (null != cancelWaitHandle)
|
||||||
|
@ -450,7 +517,7 @@ namespace Amib.Threading.Internal
|
||||||
// We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle
|
// We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle
|
||||||
// won't affect it.
|
// won't affect it.
|
||||||
// Each iteration we update the time left for the timeout.
|
// Each iteration we update the time left for the timeout.
|
||||||
for(int i = 0; i < workItemResults.Length; ++i)
|
for (int i = 0; i < waitableResults.Length; ++i)
|
||||||
{
|
{
|
||||||
// WaitAny don't work with negative numbers
|
// WaitAny don't work with negative numbers
|
||||||
if (!waitInfinitely && (millisecondsLeft < 0))
|
if (!waitInfinitely && (millisecondsLeft < 0))
|
||||||
|
@ -460,8 +527,8 @@ namespace Amib.Threading.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
whs[0] = waitHandles[i];
|
whs[0] = waitHandles[i];
|
||||||
int result = WaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
|
int result = STPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
|
||||||
if((result > 0) || (WaitHandle.WaitTimeout == result))
|
if ((result > 0) || (STPEventWaitHandle.WaitTimeout == result))
|
||||||
{
|
{
|
||||||
success = false;
|
success = false;
|
||||||
break;
|
break;
|
||||||
|
@ -470,13 +537,12 @@ namespace Amib.Threading.Internal
|
||||||
if (!waitInfinitely)
|
if (!waitInfinitely)
|
||||||
{
|
{
|
||||||
// Update the time left to wait
|
// Update the time left to wait
|
||||||
TimeSpan ts = DateTime.Now - start;
|
millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds;
|
||||||
millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Release the wait handles
|
// Release the wait handles
|
||||||
ReleaseWaitHandles(workItemResults);
|
ReleaseWaitHandles(waitableResults);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -484,7 +550,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Waits for any of the work items in the specified array to complete, cancel, or timeout
|
/// Waits for any of the work items in the specified array to complete, cancel, or timeout
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItemResults">Array of work item result objects</param>
|
/// <param name="waitableResults">Array of work item result objects</param>
|
||||||
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
|
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
|
||||||
/// <param name="exitContext">
|
/// <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.
|
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
|
||||||
|
@ -494,37 +560,37 @@ namespace Amib.Threading.Internal
|
||||||
/// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
|
/// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
internal static int WaitAny(
|
internal static int WaitAny(
|
||||||
IWorkItemResult [] workItemResults,
|
IWaitableResult[] waitableResults,
|
||||||
int millisecondsTimeout,
|
int millisecondsTimeout,
|
||||||
bool exitContext,
|
bool exitContext,
|
||||||
WaitHandle cancelWaitHandle)
|
WaitHandle cancelWaitHandle)
|
||||||
{
|
{
|
||||||
WaitHandle [] waitHandles = null;
|
WaitHandle[] waitHandles;
|
||||||
|
|
||||||
if (null != cancelWaitHandle)
|
if (null != cancelWaitHandle)
|
||||||
{
|
{
|
||||||
waitHandles = new WaitHandle[workItemResults.Length+1];
|
waitHandles = new WaitHandle[waitableResults.Length + 1];
|
||||||
GetWaitHandles(workItemResults, waitHandles);
|
GetWaitHandles(waitableResults, waitHandles);
|
||||||
waitHandles[workItemResults.Length] = cancelWaitHandle;
|
waitHandles[waitableResults.Length] = cancelWaitHandle;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
waitHandles = new WaitHandle[workItemResults.Length];
|
waitHandles = new WaitHandle[waitableResults.Length];
|
||||||
GetWaitHandles(workItemResults, waitHandles);
|
GetWaitHandles(waitableResults, waitHandles);
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
|
int result = STPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
|
||||||
|
|
||||||
// Treat cancel as timeout
|
// Treat cancel as timeout
|
||||||
if (null != cancelWaitHandle)
|
if (null != cancelWaitHandle)
|
||||||
{
|
{
|
||||||
if (result == workItemResults.Length)
|
if (result == waitableResults.Length)
|
||||||
{
|
{
|
||||||
result = WaitHandle.WaitTimeout;
|
result = STPEventWaitHandle.WaitTimeout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseWaitHandles(workItemResults);
|
ReleaseWaitHandles(waitableResults);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -532,16 +598,16 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fill an array of wait handles with the work items wait handles.
|
/// Fill an array of wait handles with the work items wait handles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItemResults">An array of work item results</param>
|
/// <param name="waitableResults">An array of work item results</param>
|
||||||
/// <param name="waitHandles">An array of wait handles to fill</param>
|
/// <param name="waitHandles">An array of wait handles to fill</param>
|
||||||
private static void GetWaitHandles(
|
private static void GetWaitHandles(
|
||||||
IWorkItemResult [] workItemResults,
|
IWaitableResult[] waitableResults,
|
||||||
WaitHandle[] waitHandles)
|
WaitHandle[] waitHandles)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < workItemResults.Length; ++i)
|
for (int i = 0; i < waitableResults.Length; ++i)
|
||||||
{
|
{
|
||||||
WorkItemResult wir = workItemResults[i] as WorkItemResult;
|
WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult;
|
||||||
Debug.Assert(null != wir, "All workItemResults must be WorkItemResult objects");
|
Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects");
|
||||||
|
|
||||||
waitHandles[i] = wir.GetWorkItem().GetWaitHandle();
|
waitHandles[i] = wir.GetWorkItem().GetWaitHandle();
|
||||||
}
|
}
|
||||||
|
@ -550,31 +616,52 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Release the work items' wait handles
|
/// Release the work items' wait handles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItemResults">An array of work item results</param>
|
/// <param name="waitableResults">An array of work item results</param>
|
||||||
private static void ReleaseWaitHandles(IWorkItemResult [] workItemResults)
|
private static void ReleaseWaitHandles(IWaitableResult[] waitableResults)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < workItemResults.Length; ++i)
|
for (int i = 0; i < waitableResults.Length; ++i)
|
||||||
{
|
{
|
||||||
WorkItemResult wir = workItemResults[i] as WorkItemResult;
|
WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult();
|
||||||
|
|
||||||
wir.GetWorkItem().ReleaseWaitHandle();
|
wir.GetWorkItem().ReleaseWaitHandle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Members
|
#region Private Members
|
||||||
|
|
||||||
private WorkItemState GetWorkItemState()
|
private WorkItemState GetWorkItemState()
|
||||||
{
|
{
|
||||||
if (_canceledWorkItemsGroup.IsCanceled)
|
lock (this)
|
||||||
|
{
|
||||||
|
if (WorkItemState.Completed == _workItemState)
|
||||||
|
{
|
||||||
|
return _workItemState;
|
||||||
|
}
|
||||||
|
|
||||||
|
long nowTicks = DateTime.UtcNow.Ticks;
|
||||||
|
|
||||||
|
if (WorkItemState.Canceled != _workItemState && nowTicks > _expirationTime)
|
||||||
|
{
|
||||||
|
_workItemState = WorkItemState.Canceled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WorkItemState.InProgress == _workItemState)
|
||||||
|
{
|
||||||
|
return _workItemState;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CanceledSmartThreadPool.IsCanceled || CanceledWorkItemsGroup.IsCanceled)
|
||||||
{
|
{
|
||||||
return WorkItemState.Canceled;
|
return WorkItemState.Canceled;
|
||||||
}
|
}
|
||||||
return _workItemState;
|
|
||||||
|
|
||||||
|
return _workItemState;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the work item's state
|
/// Sets the work item's state
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -582,10 +669,13 @@ namespace Amib.Threading.Internal
|
||||||
private void SetWorkItemState(WorkItemState workItemState)
|
private void SetWorkItemState(WorkItemState workItemState)
|
||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
|
{
|
||||||
|
if (IsValidStatesTransition(_workItemState, workItemState))
|
||||||
{
|
{
|
||||||
_workItemState = workItemState;
|
_workItemState = workItemState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Signals that work item has been completed or canceled
|
/// Signals that work item has been completed or canceled
|
||||||
|
@ -606,7 +696,7 @@ namespace Amib.Threading.Internal
|
||||||
|
|
||||||
internal void WorkItemIsQueued()
|
internal void WorkItemIsQueued()
|
||||||
{
|
{
|
||||||
_queuedTime = DateTime.Now;
|
_waitingOnQueueStopwatch.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -617,29 +707,72 @@ namespace Amib.Threading.Internal
|
||||||
/// Cancel the work item if it didn't start running yet.
|
/// Cancel the work item if it didn't start running yet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
|
/// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
|
||||||
private bool Cancel()
|
private bool Cancel(bool abortExecution)
|
||||||
{
|
{
|
||||||
|
#if (_WINDOWS_CE)
|
||||||
|
if(abortExecution)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
bool success = false;
|
||||||
|
bool signalComplete = false;
|
||||||
|
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
switch (GetWorkItemState())
|
switch (GetWorkItemState())
|
||||||
{
|
{
|
||||||
case WorkItemState.Canceled:
|
case WorkItemState.Canceled:
|
||||||
//Debug.WriteLine("Work item already canceled");
|
//Debug.WriteLine("Work item already canceled");
|
||||||
return true;
|
if (abortExecution)
|
||||||
|
{
|
||||||
|
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
|
||||||
|
if (null != executionThread)
|
||||||
|
{
|
||||||
|
executionThread.Abort(); // "Cancel"
|
||||||
|
// No need to signalComplete, because we already cancelled this work item
|
||||||
|
// so it already signaled its completion.
|
||||||
|
//signalComplete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
case WorkItemState.Completed:
|
case WorkItemState.Completed:
|
||||||
case WorkItemState.InProgress:
|
|
||||||
//Debug.WriteLine("Work item cannot be canceled");
|
//Debug.WriteLine("Work item cannot be canceled");
|
||||||
return false;
|
break;
|
||||||
|
case WorkItemState.InProgress:
|
||||||
|
if (abortExecution)
|
||||||
|
{
|
||||||
|
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
|
||||||
|
if (null != executionThread)
|
||||||
|
{
|
||||||
|
executionThread.Abort(); // "Cancel"
|
||||||
|
success = true;
|
||||||
|
signalComplete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
signalComplete = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case WorkItemState.InQueue:
|
case WorkItemState.InQueue:
|
||||||
// Signal to the wait for completion that the work
|
// Signal to the wait for completion that the work
|
||||||
// item has been completed (canceled). There is no
|
// item has been completed (canceled). There is no
|
||||||
// reason to wait for it to get out of the queue
|
// reason to wait for it to get out of the queue
|
||||||
SignalComplete(true);
|
signalComplete = true;
|
||||||
//Debug.WriteLine("Work item canceled");
|
//Debug.WriteLine("Work item canceled");
|
||||||
return true;
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signalComplete)
|
||||||
|
{
|
||||||
|
SignalComplete(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -653,7 +786,7 @@ namespace Amib.Threading.Internal
|
||||||
bool exitContext,
|
bool exitContext,
|
||||||
WaitHandle cancelWaitHandle)
|
WaitHandle cancelWaitHandle)
|
||||||
{
|
{
|
||||||
Exception e = null;
|
Exception e;
|
||||||
object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
|
object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
|
||||||
if (null != e)
|
if (null != e)
|
||||||
{
|
{
|
||||||
|
@ -694,7 +827,7 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
WaitHandle wh = GetWaitHandle();
|
WaitHandle wh = GetWaitHandle();
|
||||||
|
|
||||||
bool timeout = !wh.WaitOne(millisecondsTimeout, exitContext);
|
bool timeout = !STPEventWaitHandle.WaitOne(wh, millisecondsTimeout, exitContext);
|
||||||
|
|
||||||
ReleaseWaitHandle();
|
ReleaseWaitHandle();
|
||||||
|
|
||||||
|
@ -706,7 +839,7 @@ namespace Amib.Threading.Internal
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WaitHandle wh = GetWaitHandle();
|
WaitHandle wh = GetWaitHandle();
|
||||||
int result = WaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
|
int result = STPEventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
|
||||||
ReleaseWaitHandle();
|
ReleaseWaitHandle();
|
||||||
|
|
||||||
switch (result)
|
switch (result)
|
||||||
|
@ -717,7 +850,7 @@ namespace Amib.Threading.Internal
|
||||||
// work item (not the get result)
|
// work item (not the get result)
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
case WaitHandle.WaitTimeout:
|
case STPEventWaitHandle.WaitTimeout:
|
||||||
throw new WorkItemTimeoutException("Work item timeout");
|
throw new WorkItemTimeoutException("Work item timeout");
|
||||||
default:
|
default:
|
||||||
Debug.Assert(false);
|
Debug.Assert(false);
|
||||||
|
@ -749,7 +882,7 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
if (null == _workItemCompleted)
|
if (null == _workItemCompleted)
|
||||||
{
|
{
|
||||||
_workItemCompleted = new ManualResetEvent(IsCompleted);
|
_workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted);
|
||||||
}
|
}
|
||||||
++_workItemCompletedRefCount;
|
++_workItemCompletedRefCount;
|
||||||
}
|
}
|
||||||
|
@ -843,172 +976,6 @@ namespace Amib.Threading.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region WorkItemResult class
|
|
||||||
|
|
||||||
private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A back reference to the work item
|
|
||||||
/// </summary>
|
|
||||||
private WorkItem _workItem;
|
|
||||||
|
|
||||||
public WorkItemResult(WorkItem workItem)
|
|
||||||
{
|
|
||||||
_workItem = workItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal WorkItem GetWorkItem()
|
|
||||||
{
|
|
||||||
return _workItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region IWorkItemResult Members
|
|
||||||
|
|
||||||
public bool IsCompleted
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _workItem.IsCompleted;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Abort()
|
|
||||||
{
|
|
||||||
_workItem.Abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 _workItem.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public void DisposeOfState()
|
public void DisposeOfState()
|
||||||
{
|
{
|
||||||
if (_workItemInfo.DisposeOfStateObjects)
|
if (_workItemInfo.DisposeOfStateObjects)
|
||||||
|
@ -1021,15 +988,5 @@ namespace Amib.Threading.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Abort()
|
|
||||||
{
|
|
||||||
lock (this)
|
|
||||||
{
|
|
||||||
if(currentThread != null)
|
|
||||||
currentThread.Abort();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
// Ami Bar
|
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Amib.Threading.Internal
|
namespace Amib.Threading.Internal
|
||||||
|
@ -12,6 +9,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <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="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>
|
||||||
|
@ -26,6 +24,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <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="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>
|
||||||
|
@ -42,6 +41,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <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>
|
||||||
|
@ -63,6 +63,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <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="callback">A callback to execute</param>
|
/// <param name="callback">A callback to execute</param>
|
||||||
/// <param name="state">
|
/// <param name="state">
|
||||||
|
@ -83,6 +84,7 @@ namespace Amib.Threading.Internal
|
||||||
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
||||||
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
|
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||||
|
|
||||||
WorkItem workItem = new WorkItem(
|
WorkItem workItem = new WorkItem(
|
||||||
workItemsGroup,
|
workItemsGroup,
|
||||||
|
@ -95,6 +97,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new work item
|
/// Create a new work item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
/// <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="state">
|
/// <param name="state">
|
||||||
|
@ -131,6 +134,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new work item
|
/// Create a new work item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
/// <param name="wigStartInfo">Work item group start information</param>
|
/// <param name="wigStartInfo">Work item group start information</param>
|
||||||
/// <param name="workItemInfo">Work item information</param>
|
/// <param name="workItemInfo">Work item information</param>
|
||||||
/// <param name="callback">A callback to execute</param>
|
/// <param name="callback">A callback to execute</param>
|
||||||
|
@ -160,6 +164,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new work item
|
/// Create a new work item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
/// <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="state">
|
/// <param name="state">
|
||||||
|
@ -185,6 +190,7 @@ namespace Amib.Threading.Internal
|
||||||
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||||
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
|
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||||
|
|
||||||
WorkItem workItem = new WorkItem(
|
WorkItem workItem = new WorkItem(
|
||||||
workItemsGroup,
|
workItemsGroup,
|
||||||
|
@ -198,6 +204,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new work item
|
/// Create a new work item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
/// <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="state">
|
/// <param name="state">
|
||||||
|
@ -239,6 +246,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new work item
|
/// Create a new work item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
/// <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="state">
|
/// <param name="state">
|
||||||
|
@ -266,6 +274,7 @@ namespace Amib.Threading.Internal
|
||||||
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||||
workItemInfo.CallToPostExecute = callToPostExecute;
|
workItemInfo.CallToPostExecute = callToPostExecute;
|
||||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||||
|
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||||
|
|
||||||
WorkItem workItem = new WorkItem(
|
WorkItem workItem = new WorkItem(
|
||||||
workItemsGroup,
|
workItemsGroup,
|
||||||
|
@ -279,6 +288,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new work item
|
/// Create a new work item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="workItemsGroup">The work items group</param>
|
||||||
/// <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="state">
|
/// <param name="state">
|
||||||
|
@ -322,7 +332,7 @@ namespace Amib.Threading.Internal
|
||||||
|
|
||||||
private static void ValidateCallback(Delegate callback)
|
private static void ValidateCallback(Delegate callback)
|
||||||
{
|
{
|
||||||
if(callback.GetInvocationList().Length > 1)
|
if (callback != null && callback.GetInvocationList().Length > 1)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
|
throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
// Ami Bar
|
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
namespace Amib.Threading
|
namespace Amib.Threading
|
||||||
{
|
{
|
||||||
#region WorkItemInfo class
|
#region WorkItemInfo class
|
||||||
|
@ -10,92 +7,62 @@ namespace Amib.Threading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WorkItemInfo
|
public class WorkItemInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Use the caller's security context
|
|
||||||
/// </summary>
|
|
||||||
private bool _useCallerCallContext;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Use the caller's security context
|
|
||||||
/// </summary>
|
|
||||||
private bool _useCallerHttpContext;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dispose of the state object of a work item
|
|
||||||
/// </summary>
|
|
||||||
private bool _disposeOfStateObjects;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The option to run the post execute
|
|
||||||
/// </summary>
|
|
||||||
private CallToPostExecute _callToPostExecute;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A post execute callback to call when none is provided in
|
|
||||||
/// the QueueWorkItem method.
|
|
||||||
/// </summary>
|
|
||||||
private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The priority of the work item
|
|
||||||
/// </summary>
|
|
||||||
private WorkItemPriority _workItemPriority;
|
|
||||||
|
|
||||||
public WorkItemInfo()
|
public WorkItemInfo()
|
||||||
{
|
{
|
||||||
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
||||||
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
||||||
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
||||||
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
||||||
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
||||||
_workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
|
WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorkItemInfo(WorkItemInfo workItemInfo)
|
public WorkItemInfo(WorkItemInfo workItemInfo)
|
||||||
{
|
{
|
||||||
_useCallerCallContext = workItemInfo._useCallerCallContext;
|
UseCallerCallContext = workItemInfo.UseCallerCallContext;
|
||||||
_useCallerHttpContext = workItemInfo._useCallerHttpContext;
|
UseCallerHttpContext = workItemInfo.UseCallerHttpContext;
|
||||||
_disposeOfStateObjects = workItemInfo._disposeOfStateObjects;
|
DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects;
|
||||||
_callToPostExecute = workItemInfo._callToPostExecute;
|
CallToPostExecute = workItemInfo.CallToPostExecute;
|
||||||
_postExecuteWorkItemCallback = workItemInfo._postExecuteWorkItemCallback;
|
PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback;
|
||||||
_workItemPriority = workItemInfo._workItemPriority;
|
WorkItemPriority = workItemInfo.WorkItemPriority;
|
||||||
|
Timeout = workItemInfo.Timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UseCallerCallContext
|
/// <summary>
|
||||||
{
|
/// Get/Set if to use the caller's security context
|
||||||
get { return _useCallerCallContext; }
|
/// </summary>
|
||||||
set { _useCallerCallContext = value; }
|
public bool UseCallerCallContext { get; set; }
|
||||||
}
|
|
||||||
|
|
||||||
public bool UseCallerHttpContext
|
/// <summary>
|
||||||
{
|
/// Get/Set if to use the caller's HTTP context
|
||||||
get { return _useCallerHttpContext; }
|
/// </summary>
|
||||||
set { _useCallerHttpContext = value; }
|
public bool UseCallerHttpContext { get; set; }
|
||||||
}
|
|
||||||
|
|
||||||
public bool DisposeOfStateObjects
|
/// <summary>
|
||||||
{
|
/// Get/Set if to dispose of the state object of a work item
|
||||||
get { return _disposeOfStateObjects; }
|
/// </summary>
|
||||||
set { _disposeOfStateObjects = value; }
|
public bool DisposeOfStateObjects { get; set; }
|
||||||
}
|
|
||||||
|
|
||||||
public CallToPostExecute CallToPostExecute
|
/// <summary>
|
||||||
{
|
/// Get/Set the run the post execute options
|
||||||
get { return _callToPostExecute; }
|
/// </summary>
|
||||||
set { _callToPostExecute = value; }
|
public CallToPostExecute CallToPostExecute { get; set; }
|
||||||
}
|
|
||||||
|
|
||||||
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
|
/// <summary>
|
||||||
{
|
/// Get/Set the post execute callback
|
||||||
get { return _postExecuteWorkItemCallback; }
|
/// </summary>
|
||||||
set { _postExecuteWorkItemCallback = value; }
|
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; }
|
||||||
}
|
|
||||||
|
|
||||||
public WorkItemPriority WorkItemPriority
|
/// <summary>
|
||||||
{
|
/// Get/Set the work item's priority
|
||||||
get { return _workItemPriority; }
|
/// </summary>
|
||||||
set { _workItemPriority = value; }
|
public WorkItemPriority WorkItemPriority { get; set; }
|
||||||
}
|
|
||||||
|
/// <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!
|
||||||
|
/// </summary>
|
||||||
|
public long Timeout { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,3 @@
|
||||||
// Ami Bar
|
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
@ -8,33 +5,34 @@ using System.Diagnostics;
|
||||||
|
|
||||||
namespace Amib.Threading.Internal
|
namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
|
|
||||||
#region WorkItemsGroup class
|
#region WorkItemsGroup class
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Summary description for WorkItemsGroup.
|
/// Summary description for WorkItemsGroup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WorkItemsGroup : IWorkItemsGroup
|
public class WorkItemsGroup : WorkItemsGroupBase
|
||||||
{
|
{
|
||||||
#region Private members
|
#region Private members
|
||||||
|
|
||||||
private object _lock = new object();
|
private readonly object _lock = new object();
|
||||||
/// <summary>
|
|
||||||
/// Contains the name of this instance of SmartThreadPool.
|
|
||||||
/// Can be changed by the user.
|
|
||||||
/// </summary>
|
|
||||||
private string _name = "WorkItemsGroup";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A reference to the SmartThreadPool instance that created this
|
/// A reference to the SmartThreadPool instance that created this
|
||||||
/// WorkItemsGroup.
|
/// WorkItemsGroup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private SmartThreadPool _stp;
|
private readonly SmartThreadPool _stp;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The OnIdle event
|
/// The OnIdle event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private event WorkItemsGroupIdleHandler _onIdle;
|
private event WorkItemsGroupIdleHandler _onIdle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A flag to indicate if the Work Items Group is now suspended.
|
||||||
|
/// </summary>
|
||||||
|
private bool _isSuspended;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines how many work items of this WorkItemsGroup can run at once.
|
/// Defines how many work items of this WorkItemsGroup can run at once.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -44,7 +42,7 @@ namespace Amib.Threading.Internal
|
||||||
/// Priority queue to hold work items before they are passed
|
/// Priority queue to hold work items before they are passed
|
||||||
/// to the SmartThreadPool.
|
/// to the SmartThreadPool.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private PriorityQueue _workItemsQueue;
|
private readonly PriorityQueue _workItemsQueue;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicate how many work items are waiting in the SmartThreadPool
|
/// Indicate how many work items are waiting in the SmartThreadPool
|
||||||
|
@ -63,12 +61,13 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WorkItemsGroup start information
|
/// WorkItemsGroup start information
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private WIGStartInfo _workItemsGroupStartInfo;
|
private readonly WIGStartInfo _workItemsGroupStartInfo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Signaled when all of the WorkItemsGroup's work item completed.
|
/// Signaled when all of the WorkItemsGroup's work item completed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
|
//private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
|
||||||
|
private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(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
|
||||||
|
@ -87,261 +86,90 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
if (concurrency <= 0)
|
if (concurrency <= 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("concurrency", concurrency, "concurrency must be greater than zero");
|
throw new ArgumentOutOfRangeException(
|
||||||
|
"concurrency",
|
||||||
|
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||||
|
concurrency,
|
||||||
|
#endif
|
||||||
|
"concurrency must be greater than zero");
|
||||||
}
|
}
|
||||||
_stp = stp;
|
_stp = stp;
|
||||||
_concurrency = concurrency;
|
_concurrency = concurrency;
|
||||||
_workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo);
|
_workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly();
|
||||||
_workItemsQueue = new PriorityQueue();
|
_workItemsQueue = new PriorityQueue();
|
||||||
|
Name = "WorkItemsGroup";
|
||||||
|
|
||||||
// The _workItemsInStpQueue gets the number of currently executing work items,
|
// The _workItemsInStpQueue gets the number of currently executing work items,
|
||||||
// because once a work item is executing, it cannot be cancelled.
|
// because once a work item is executing, it cannot be cancelled.
|
||||||
_workItemsInStpQueue = _workItemsExecutingInStp;
|
_workItemsInStpQueue = _workItemsExecutingInStp;
|
||||||
|
|
||||||
|
_isSuspended = _workItemsGroupStartInfo.StartSuspended;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IWorkItemsGroup implementation
|
#region WorkItemsGroupBase Overrides
|
||||||
|
|
||||||
/// <summary>
|
public override int Concurrency
|
||||||
/// Get/Set the name of the SmartThreadPool instance
|
|
||||||
/// </summary>
|
|
||||||
public string Name
|
|
||||||
{
|
{
|
||||||
get
|
get { return _concurrency; }
|
||||||
{
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_name = value;
|
Debug.Assert(value > 0);
|
||||||
|
|
||||||
|
int diff = value - _concurrency;
|
||||||
|
_concurrency = value;
|
||||||
|
if (diff > 0)
|
||||||
|
{
|
||||||
|
EnqueueToSTPNextNWorkItem(diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int WaitingCallbacks
|
||||||
|
{
|
||||||
|
get { return _workItemsQueue.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object[] GetStates()
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
object[] states = new object[_workItemsQueue.Count];
|
||||||
|
int i = 0;
|
||||||
|
foreach (WorkItem workItem in _workItemsQueue)
|
||||||
|
{
|
||||||
|
states[i] = workItem.GetWorkItemResult().State;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return states;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queue a work item
|
/// WorkItemsGroup start information
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="callback">A callback to execute</param>
|
public override WIGStartInfo WIGStartInfo
|
||||||
/// <returns>Returns a work item result</returns>
|
|
||||||
public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
|
|
||||||
{
|
{
|
||||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback);
|
get { return _workItemsGroupStartInfo; }
|
||||||
EnqueueToSTPNextWorkItem(workItem);
|
|
||||||
return workItem.GetWorkItemResult();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queue a work item
|
/// Start the Work Items Group if it was started suspended
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="callback">A callback to execute</param>
|
public override void Start()
|
||||||
/// <param name="workItemPriority">The priority of the work item</param>
|
|
||||||
/// <returns>Returns a work item result</returns>
|
|
||||||
public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority)
|
|
||||||
{
|
{
|
||||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, workItemPriority);
|
// If the Work Items Group already started then quit
|
||||||
EnqueueToSTPNextWorkItem(workItem);
|
if (!_isSuspended)
|
||||||
return workItem.GetWorkItemResult();
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_isSuspended = false;
|
||||||
|
|
||||||
|
EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public override void Cancel(bool abortExecution)
|
||||||
/// 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)
|
|
||||||
{
|
|
||||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback);
|
|
||||||
EnqueueToSTPNextWorkItem(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, _workItemsGroupStartInfo, callback, state);
|
|
||||||
EnqueueToSTPNextWorkItem(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)
|
|
||||||
{
|
|
||||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, workItemPriority);
|
|
||||||
EnqueueToSTPNextWorkItem(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)
|
|
||||||
{
|
|
||||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback, state);
|
|
||||||
EnqueueToSTPNextWorkItem(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)
|
|
||||||
{
|
|
||||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback);
|
|
||||||
EnqueueToSTPNextWorkItem(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)
|
|
||||||
{
|
|
||||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
|
|
||||||
EnqueueToSTPNextWorkItem(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)
|
|
||||||
{
|
|
||||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
|
|
||||||
EnqueueToSTPNextWorkItem(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)
|
|
||||||
{
|
|
||||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority);
|
|
||||||
EnqueueToSTPNextWorkItem(workItem);
|
|
||||||
return workItem.GetWorkItemResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wait for the thread pool to be idle
|
|
||||||
/// </summary>
|
|
||||||
public void WaitForIdle()
|
|
||||||
{
|
|
||||||
WaitForIdle(Timeout.Infinite);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wait for the thread pool to be idle
|
|
||||||
/// </summary>
|
|
||||||
public bool WaitForIdle(TimeSpan timeout)
|
|
||||||
{
|
|
||||||
return WaitForIdle((int)timeout.TotalMilliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wait for the thread pool to be idle
|
|
||||||
/// </summary>
|
|
||||||
public bool WaitForIdle(int millisecondsTimeout)
|
|
||||||
{
|
|
||||||
_stp.ValidateWorkItemsGroupWaitForIdle(this);
|
|
||||||
return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int WaitingCallbacks
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _workItemsQueue.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public event WorkItemsGroupIdleHandler OnIdle
|
|
||||||
{
|
|
||||||
add
|
|
||||||
{
|
|
||||||
_onIdle += value;
|
|
||||||
}
|
|
||||||
remove
|
|
||||||
{
|
|
||||||
_onIdle -= value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Cancel()
|
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
|
@ -350,23 +178,26 @@ namespace Amib.Threading.Internal
|
||||||
_workItemsInStpQueue = 0;
|
_workItemsInStpQueue = 0;
|
||||||
_canceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
_canceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (abortExecution)
|
||||||
|
{
|
||||||
|
_stp.CancelAbortWorkItemsGroup(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
/// <summary>
|
||||||
|
/// Wait for the thread pool to be idle
|
||||||
|
/// </summary>
|
||||||
|
public override bool WaitForIdle(int millisecondsTimeout)
|
||||||
{
|
{
|
||||||
lock (this)
|
SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
|
||||||
{
|
return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
|
||||||
if (!_workItemsGroupStartInfo.StartSuspended)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_workItemsGroupStartInfo.StartSuspended = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < _concurrency; ++i)
|
public override event WorkItemsGroupIdleHandler OnIdle
|
||||||
{
|
{
|
||||||
EnqueueToSTPNextWorkItem(null, false);
|
add { _onIdle += value; }
|
||||||
}
|
remove { _onIdle -= value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -375,22 +206,24 @@ namespace Amib.Threading.Internal
|
||||||
|
|
||||||
private void RegisterToWorkItemCompletion(IWorkItemResult wir)
|
private void RegisterToWorkItemCompletion(IWorkItemResult wir)
|
||||||
{
|
{
|
||||||
IInternalWorkItemResult iwir = wir as IInternalWorkItemResult;
|
IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir;
|
||||||
iwir.OnWorkItemStarted += new WorkItemStateCallback(OnWorkItemStartedCallback);
|
iwir.OnWorkItemStarted += OnWorkItemStartedCallback;
|
||||||
iwir.OnWorkItemCompleted += new WorkItemStateCallback(OnWorkItemCompletedCallback);
|
iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnSTPIsStarting()
|
public void OnSTPIsStarting()
|
||||||
{
|
{
|
||||||
lock (this)
|
if (_isSuspended)
|
||||||
{
|
|
||||||
if (_workItemsGroupStartInfo.StartSuspended)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnqueueToSTPNextNWorkItem(_concurrency);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < _concurrency; ++i)
|
public void EnqueueToSTPNextNWorkItem(int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
EnqueueToSTPNextWorkItem(null, false);
|
EnqueueToSTPNextWorkItem(null, false);
|
||||||
}
|
}
|
||||||
|
@ -417,8 +250,7 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
eh(this);
|
eh(this);
|
||||||
}
|
}
|
||||||
// Ignore exceptions
|
catch { } // Suppress exceptions
|
||||||
catch{}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,6 +267,11 @@ namespace Amib.Threading.Internal
|
||||||
EnqueueToSTPNextWorkItem(null, true);
|
EnqueueToSTPNextWorkItem(null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Enqueue(WorkItem workItem)
|
||||||
|
{
|
||||||
|
EnqueueToSTPNextWorkItem(workItem);
|
||||||
|
}
|
||||||
|
|
||||||
private void EnqueueToSTPNextWorkItem(WorkItem workItem)
|
private void EnqueueToSTPNextWorkItem(WorkItem workItem)
|
||||||
{
|
{
|
||||||
EnqueueToSTPNextWorkItem(workItem, false);
|
EnqueueToSTPNextWorkItem(workItem, false);
|
||||||
|
@ -475,7 +312,7 @@ namespace Amib.Threading.Internal
|
||||||
(0 == _workItemsInStpQueue))
|
(0 == _workItemsInStpQueue))
|
||||||
{
|
{
|
||||||
_stp.RegisterWorkItemsGroup(this);
|
_stp.RegisterWorkItemsGroup(this);
|
||||||
Trace.WriteLine("WorkItemsGroup " + Name + " is NOT idle");
|
IsIdle = false;
|
||||||
_isIdleWaitHandle.Reset();
|
_isIdleWaitHandle.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,19 +323,31 @@ namespace Amib.Threading.Internal
|
||||||
if (0 == _workItemsInStpQueue)
|
if (0 == _workItemsInStpQueue)
|
||||||
{
|
{
|
||||||
_stp.UnregisterWorkItemsGroup(this);
|
_stp.UnregisterWorkItemsGroup(this);
|
||||||
Trace.WriteLine("WorkItemsGroup " + Name + " is idle");
|
IsIdle = true;
|
||||||
_isIdleWaitHandle.Set();
|
_isIdleWaitHandle.Set();
|
||||||
_stp.QueueWorkItem(new WorkItemCallback(this.FireOnIdle));
|
if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0)
|
||||||
|
{
|
||||||
|
_stp.QueueWorkItem(new WorkItemCallback(FireOnIdle));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_workItemsGroupStartInfo.StartSuspended)
|
if (!_isSuspended)
|
||||||
{
|
{
|
||||||
if (_workItemsInStpQueue < _concurrency)
|
if (_workItemsInStpQueue < _concurrency)
|
||||||
{
|
{
|
||||||
WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
|
WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
|
||||||
_stp.Enqueue(nextWorkItem, true);
|
try
|
||||||
|
{
|
||||||
|
_stp.Enqueue(nextWorkItem);
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException e)
|
||||||
|
{
|
||||||
|
e.GetHashCode();
|
||||||
|
// The STP has been shutdown
|
||||||
|
}
|
||||||
|
|
||||||
++_workItemsInStpQueue;
|
++_workItemsInStpQueue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
// Ami Bar
|
|
||||||
// amibar@gmail.com
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Amib.Threading.Internal
|
namespace Amib.Threading.Internal
|
||||||
|
@ -18,7 +16,7 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Waiters queue (implemented as stack).
|
/// Waiters queue (implemented as stack).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private WaiterEntry _headWaiterEntry = new WaiterEntry();
|
private readonly WaiterEntry _headWaiterEntry = new WaiterEntry();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Waiters count
|
/// Waiters count
|
||||||
|
@ -28,18 +26,70 @@ namespace Amib.Threading.Internal
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Work items queue
|
/// Work items queue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private PriorityQueue _workItems = new PriorityQueue();
|
private readonly PriorityQueue _workItems = new PriorityQueue();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicate that work items are allowed to be queued
|
/// Indicate that work items are allowed to be queued
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool _isWorkItemsQueueActive = true;
|
private bool _isWorkItemsQueueActive = true;
|
||||||
|
|
||||||
|
|
||||||
|
#if (WINDOWS_PHONE)
|
||||||
|
private static readonly Dictionary<int, WaiterEntry> _waiterEntries = new Dictionary<int, WaiterEntry>();
|
||||||
|
#elif (_WINDOWS_CE)
|
||||||
|
private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot();
|
||||||
|
#else
|
||||||
|
|
||||||
|
[ThreadStatic]
|
||||||
|
private static WaiterEntry _waiterEntry;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Each thread in the thread pool keeps its own waiter entry.
|
/// Each thread in the thread pool keeps its own waiter entry.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ThreadStatic]
|
private static WaiterEntry CurrentWaiterEntry
|
||||||
private static WaiterEntry _waiterEntry;
|
{
|
||||||
|
#if (WINDOWS_PHONE)
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_waiterEntries)
|
||||||
|
{
|
||||||
|
WaiterEntry waiterEntry;
|
||||||
|
if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry))
|
||||||
|
{
|
||||||
|
return waiterEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
lock (_waiterEntries)
|
||||||
|
{
|
||||||
|
_waiterEntries[Thread.CurrentThread.ManagedThreadId] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif (_WINDOWS_CE)
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Thread.GetData(_waiterEntrySlot) as WaiterEntry;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Thread.SetData(_waiterEntrySlot, value);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _waiterEntry;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_waiterEntry = value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A flag that indicates if the WorkItemsQueue has been disposed.
|
/// A flag that indicates if the WorkItemsQueue has been disposed.
|
||||||
|
@ -57,13 +107,9 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
lock(this)
|
|
||||||
{
|
|
||||||
ValidateNotDisposed();
|
|
||||||
return _workItems.Count;
|
return _workItems.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the current number of waiters
|
/// Returns the current number of waiters
|
||||||
|
@ -72,13 +118,9 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
lock(this)
|
|
||||||
{
|
|
||||||
ValidateNotDisposed();
|
|
||||||
return _waitersCount;
|
return _waitersCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -144,21 +186,20 @@ namespace Amib.Threading.Internal
|
||||||
int millisecondsTimeout,
|
int millisecondsTimeout,
|
||||||
WaitHandle cancelEvent)
|
WaitHandle cancelEvent)
|
||||||
{
|
{
|
||||||
/// This method cause the caller to wait for a work item.
|
// This method cause the caller to wait for a work item.
|
||||||
/// If there is at least one waiting work item then the
|
// If there is at least one waiting work item then the
|
||||||
/// method returns immidiately with true.
|
// method returns immidiately with it.
|
||||||
///
|
//
|
||||||
/// If there are no waiting work items then the caller
|
// If there are no waiting work items then the caller
|
||||||
/// is queued between other waiters for a work item to arrive.
|
// is queued between other waiters for a work item to arrive.
|
||||||
///
|
//
|
||||||
/// If a work item didn't come within millisecondsTimeout or
|
// If a work item didn't come within millisecondsTimeout or
|
||||||
/// the user canceled the wait by signaling the cancelEvent
|
// the user canceled the wait by signaling the cancelEvent
|
||||||
/// then the method returns false to indicate that the caller
|
// then the method returns null to indicate that the caller
|
||||||
/// didn't get a work item.
|
// didn't get a work item.
|
||||||
|
|
||||||
WaiterEntry waiterEntry = null;
|
WaiterEntry waiterEntry;
|
||||||
WorkItem workItem = null;
|
WorkItem workItem = null;
|
||||||
|
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
ValidateNotDisposed();
|
ValidateNotDisposed();
|
||||||
|
@ -169,16 +210,15 @@ namespace Amib.Threading.Internal
|
||||||
workItem = _workItems.Dequeue() as WorkItem;
|
workItem = _workItems.Dequeue() as WorkItem;
|
||||||
return workItem;
|
return workItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No waiting work items ...
|
// No waiting work items ...
|
||||||
else
|
|
||||||
{
|
// Get the waiter entry for the waiters queue
|
||||||
// Get the wait entry for the waiters queue
|
|
||||||
waiterEntry = GetThreadWaiterEntry();
|
waiterEntry = GetThreadWaiterEntry();
|
||||||
|
|
||||||
// Put the waiter with the other waiters
|
// Put the waiter with the other waiters
|
||||||
PushWaiter(waiterEntry);
|
PushWaiter(waiterEntry);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare array of wait handle for the WaitHandle.WaitAny()
|
// Prepare array of wait handle for the WaitHandle.WaitAny()
|
||||||
WaitHandle [] waitHandles = new WaitHandle[] {
|
WaitHandle [] waitHandles = new WaitHandle[] {
|
||||||
|
@ -189,10 +229,10 @@ namespace Amib.Threading.Internal
|
||||||
|
|
||||||
// During the wait we are supposes to exit the synchronization
|
// During the wait we are supposes to exit the synchronization
|
||||||
// domain. (Placing true as the third argument of the WaitAny())
|
// domain. (Placing true as the third argument of the WaitAny())
|
||||||
// It just doesn't work, I don't know why, so I have lock(this)
|
// It just doesn't work, I don't know why, so I have two lock(this)
|
||||||
// statments insted of one.
|
// statments instead of one.
|
||||||
|
|
||||||
int index = WaitHandle.WaitAny(
|
int index = STPEventWaitHandle.WaitAny(
|
||||||
waitHandles,
|
waitHandles,
|
||||||
millisecondsTimeout,
|
millisecondsTimeout,
|
||||||
true);
|
true);
|
||||||
|
@ -242,7 +282,7 @@ namespace Amib.Threading.Internal
|
||||||
/// Cleanup the work items queue, hence no more work
|
/// Cleanup the work items queue, hence no more work
|
||||||
/// items are allowed to be queue
|
/// items are allowed to be queue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void Cleanup()
|
private void Cleanup()
|
||||||
{
|
{
|
||||||
lock(this)
|
lock(this)
|
||||||
{
|
{
|
||||||
|
@ -279,6 +319,21 @@ namespace Amib.Threading.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object[] GetStates()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
object[] states = new object[_workItems.Count];
|
||||||
|
int i = 0;
|
||||||
|
foreach (WorkItem workItem in _workItems)
|
||||||
|
{
|
||||||
|
states[i] = workItem.GetWorkItemResult().State;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return states;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private methods
|
#region Private methods
|
||||||
|
@ -289,14 +344,14 @@ namespace Amib.Threading.Internal
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// In order to avoid creation and destuction of WaiterEntry
|
/// In order to avoid creation and destuction of WaiterEntry
|
||||||
/// objects each thread has its own WaiterEntry object.
|
/// objects each thread has its own WaiterEntry object.
|
||||||
private WaiterEntry GetThreadWaiterEntry()
|
private static WaiterEntry GetThreadWaiterEntry()
|
||||||
{
|
{
|
||||||
if (null == _waiterEntry)
|
if (null == CurrentWaiterEntry)
|
||||||
{
|
{
|
||||||
_waiterEntry = new WaiterEntry();
|
CurrentWaiterEntry = new WaiterEntry();
|
||||||
}
|
}
|
||||||
_waiterEntry.Reset();
|
CurrentWaiterEntry.Reset();
|
||||||
return _waiterEntry;
|
return CurrentWaiterEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Waiters stack methods
|
#region Waiters stack methods
|
||||||
|
@ -418,14 +473,15 @@ namespace Amib.Threading.Internal
|
||||||
#region WaiterEntry class
|
#region WaiterEntry class
|
||||||
|
|
||||||
// A waiter entry in the _waiters queue.
|
// A waiter entry in the _waiters queue.
|
||||||
public class WaiterEntry : IDisposable
|
public sealed class WaiterEntry : IDisposable
|
||||||
{
|
{
|
||||||
#region Member variables
|
#region Member variables
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event to signal the waiter that it got the work item.
|
/// Event to signal the waiter that it got the work item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private AutoResetEvent _waitHandle = new AutoResetEvent(false);
|
//private AutoResetEvent _waitHandle = new AutoResetEvent(false);
|
||||||
|
private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flag to know if this waiter already quited from the queue
|
/// Flag to know if this waiter already quited from the queue
|
||||||
|
@ -471,13 +527,10 @@ namespace Amib.Threading.Internal
|
||||||
public WorkItem WorkItem
|
public WorkItem WorkItem
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
|
||||||
lock(this)
|
|
||||||
{
|
{
|
||||||
return _workItem;
|
return _workItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Signal the waiter that it got a work item.
|
/// Signal the waiter that it got a work item.
|
||||||
|
@ -550,18 +603,16 @@ namespace Amib.Threading.Internal
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
if (!_isDisposed)
|
if (!_isDisposed)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
|
}
|
||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~WaiterEntry()
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,14 +625,8 @@ namespace Amib.Threading.Internal
|
||||||
if (!_isDisposed)
|
if (!_isDisposed)
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
|
}
|
||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~WorkItemsQueue()
|
|
||||||
{
|
|
||||||
Cleanup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateNotDisposed()
|
private void ValidateNotDisposed()
|
||||||
|
|
Loading…
Reference in New Issue