Merge branch 'master' into careminster
Conflicts: ThirdParty/SmartThreadPool/SmartThreadPool.csavinationmerge
commit
8c5445b774
|
@ -158,7 +158,7 @@ namespace OpenSim.Framework.Capabilities
|
||||||
/// capabilities and their handler details.
|
/// capabilities and their handler details.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="excludeSeed">If true, then exclude the seed cap.</param>
|
/// <param name="excludeSeed">If true, then exclude the seed cap.</param>
|
||||||
public Hashtable GetCapsDetails(bool excludeSeed)
|
public Hashtable GetCapsDetails(bool excludeSeed, List<string> requestedCaps)
|
||||||
{
|
{
|
||||||
Hashtable caps = new Hashtable();
|
Hashtable caps = new Hashtable();
|
||||||
string protocol = "http://";
|
string protocol = "http://";
|
||||||
|
@ -175,6 +175,9 @@ namespace OpenSim.Framework.Capabilities
|
||||||
if (excludeSeed && "SEED" == capsName)
|
if (excludeSeed && "SEED" == capsName)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (requestedCaps != null && !requestedCaps.Contains(capsName))
|
||||||
|
continue;
|
||||||
|
|
||||||
caps[capsName] = baseUrl + m_capsHandlers[capsName].Path;
|
caps[capsName] = baseUrl + m_capsHandlers[capsName].Path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1852,7 +1852,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); });
|
||||||
|
@ -1922,15 +1922,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
|
||||||
|
|
||||||
|
|
|
@ -355,11 +355,22 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true);
|
OSDArray capsRequested = (OSDArray)OSDParser.DeserializeLLSDXml(request);
|
||||||
|
List<string> validCaps = new List<string>();
|
||||||
|
|
||||||
|
foreach (OSD c in capsRequested)
|
||||||
|
validCaps.Add(c.AsString());
|
||||||
|
|
||||||
|
Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps);
|
||||||
|
|
||||||
// Add the external too
|
// Add the external too
|
||||||
foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
|
foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
|
||||||
|
{
|
||||||
|
if (!validCaps.Contains(kvp.Key))
|
||||||
|
continue;
|
||||||
|
|
||||||
caps[kvp.Key] = kvp.Value;
|
caps[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
|
||||||
string result = LLSDHelpers.SerialiseLLSDReply(caps);
|
string result = LLSDHelpers.SerialiseLLSDReply(caps);
|
||||||
|
|
||||||
|
|
|
@ -252,7 +252,7 @@ namespace OpenSim.Region.CoreModules.Framework
|
||||||
{
|
{
|
||||||
caps.AppendFormat("** Circuit {0}:\n", kvp.Key);
|
caps.AppendFormat("** Circuit {0}:\n", kvp.Key);
|
||||||
|
|
||||||
for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); )
|
for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); )
|
||||||
{
|
{
|
||||||
Uri uri = new Uri(kvp2.Value.ToString());
|
Uri uri = new Uri(kvp2.Value.ToString());
|
||||||
caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery);
|
caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery);
|
||||||
|
|
|
@ -676,11 +676,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (remoteClient == null || so.OwnerID != remoteClient.AgentId)
|
if (remoteClient == null || so.RootPart.OwnerID != remoteClient.AgentId)
|
||||||
{
|
{
|
||||||
// Taking copy of another person's item. Take to
|
// Taking copy of another person's item. Take to
|
||||||
// Objects folder.
|
// Objects folder.
|
||||||
folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
|
folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
|
||||||
|
so.FromFolderID = UUID.Zero;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -696,7 +697,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||||
//
|
//
|
||||||
if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
|
if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
|
||||||
{
|
{
|
||||||
if (so.FromFolderID != UUID.Zero && userID == remoteClient.AgentId)
|
if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId)
|
||||||
{
|
{
|
||||||
InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID);
|
InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID);
|
||||||
if (f != null)
|
if (f != null)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -572,9 +572,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;
|
||||||
|
|
||||||
|
|
|
@ -551,7 +551,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;
|
||||||
|
@ -1599,7 +1599,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,82 @@ 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
|
||||||
|
{
|
||||||
|
// **************************
|
||||||
|
// Stock SmartThreadPool 2.2.3 sets these to true and relies on the thread to check the
|
||||||
|
// WorkItem cancellation status. However, OpenSimulator uses a different mechanism to notify
|
||||||
|
// scripts of co-operative termination and the abort code also relies on this method
|
||||||
|
// returning false in order to implement a small wait.
|
||||||
|
//
|
||||||
|
// Therefore, as was the case previously with STP, we will not signal successful cancellation
|
||||||
|
// here. It's possible that OpenSimulator code could be changed in the future to remove
|
||||||
|
// the need for this change.
|
||||||
|
// **************************
|
||||||
|
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 +796,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 +837,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 +849,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 +860,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 +892,7 @@ namespace Amib.Threading.Internal
|
||||||
{
|
{
|
||||||
if (null == _workItemCompleted)
|
if (null == _workItemCompleted)
|
||||||
{
|
{
|
||||||
_workItemCompleted = new ManualResetEvent(IsCompleted);
|
_workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted);
|
||||||
}
|
}
|
||||||
++_workItemCompletedRefCount;
|
++_workItemCompletedRefCount;
|
||||||
}
|
}
|
||||||
|
@ -843,172 +986,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 +998,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()
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
|
; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
|
||||||
; *
|
; *
|
||||||
[Startup]
|
[Startup]
|
||||||
|
; Place to create a PID file
|
||||||
|
; If no path if specified then a PID file is not created.
|
||||||
|
; PIDFile = "/tmp/my.pid"
|
||||||
|
|
||||||
; Plugin Registry Location
|
; Plugin Registry Location
|
||||||
; Set path to directory for plugin registry. Information
|
; Set path to directory for plugin registry. Information
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
|
; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
|
||||||
; *
|
; *
|
||||||
[Startup]
|
[Startup]
|
||||||
|
; Place to create a PID file
|
||||||
|
; If no path if specified then a PID file is not created.
|
||||||
|
; PIDFile = "/tmp/my.pid"
|
||||||
|
|
||||||
; Plugin Registry Location
|
; Plugin Registry Location
|
||||||
; Set path to directory for plugin registry. Information
|
; Set path to directory for plugin registry. Information
|
||||||
|
@ -21,7 +24,6 @@
|
||||||
; The Robust.exe process must have R/W access to the location
|
; The Robust.exe process must have R/W access to the location
|
||||||
RegistryLocation = "."
|
RegistryLocation = "."
|
||||||
|
|
||||||
|
|
||||||
; Modular configurations
|
; Modular configurations
|
||||||
; Set path to directory for modular ini files...
|
; Set path to directory for modular ini files...
|
||||||
; The Robust.exe process must have R/W access to the location
|
; The Robust.exe process must have R/W access to the location
|
||||||
|
|
Loading…
Reference in New Issue