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.
|
||||
/// </summary>
|
||||
/// <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();
|
||||
string protocol = "http://";
|
||||
|
@ -175,6 +175,9 @@ namespace OpenSim.Framework.Capabilities
|
|||
if (excludeSeed && "SEED" == capsName)
|
||||
continue;
|
||||
|
||||
if (requestedCaps != null && !requestedCaps.Contains(capsName))
|
||||
continue;
|
||||
|
||||
caps[capsName] = baseUrl + m_capsHandlers[capsName].Path;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1852,7 +1852,7 @@ namespace OpenSim.Framework
|
|||
case FireAndForgetMethod.SmartThreadPool:
|
||||
if (m_ThreadPool == null)
|
||||
InitThreadPool(15);
|
||||
m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj });
|
||||
m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
|
||||
break;
|
||||
case FireAndForgetMethod.Thread:
|
||||
Thread thread = new Thread(delegate(object o) { realCallback(o); });
|
||||
|
@ -1922,15 +1922,15 @@ namespace OpenSim.Framework
|
|||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static object SmartThreadPoolCallback(object o)
|
||||
{
|
||||
object[] array = (object[])o;
|
||||
WaitCallback callback = (WaitCallback)array[0];
|
||||
object obj = array[1];
|
||||
|
||||
callback(obj);
|
||||
return null;
|
||||
}
|
||||
// private static object SmartThreadPoolCallback(object o)
|
||||
// {
|
||||
// object[] array = (object[])o;
|
||||
// WaitCallback callback = (WaitCallback)array[0];
|
||||
// object obj = array[1];
|
||||
//
|
||||
// callback(obj);
|
||||
// return null;
|
||||
// }
|
||||
|
||||
#endregion FireAndForget Threading Pattern
|
||||
|
||||
|
|
|
@ -355,11 +355,22 @@ namespace OpenSim.Region.ClientStack.Linden
|
|||
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
|
||||
foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
|
||||
{
|
||||
if (!validCaps.Contains(kvp.Key))
|
||||
continue;
|
||||
|
||||
caps[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
string result = LLSDHelpers.SerialiseLLSDReply(caps);
|
||||
|
||||
|
|
|
@ -252,7 +252,7 @@ namespace OpenSim.Region.CoreModules.Framework
|
|||
{
|
||||
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());
|
||||
caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery);
|
||||
|
|
|
@ -676,11 +676,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
|||
}
|
||||
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
|
||||
// Objects folder.
|
||||
folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
|
||||
so.FromFolderID = UUID.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -696,7 +697,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
|||
//
|
||||
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);
|
||||
if (f != null)
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
|
|||
public interface IScriptWorkItem
|
||||
{
|
||||
bool Cancel();
|
||||
void Abort();
|
||||
bool Abort();
|
||||
|
||||
/// <summary>
|
||||
/// Wait for the work item to complete.
|
||||
|
|
|
@ -572,9 +572,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
|
|||
|
||||
public bool Stop(int timeout)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}",
|
||||
// ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks);
|
||||
if (DebugLevel >= 1)
|
||||
m_log.DebugFormat(
|
||||
"[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;
|
||||
|
||||
|
|
|
@ -551,7 +551,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
|||
/// <param name="instance"></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>(
|
||||
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))
|
||||
return;
|
||||
|
@ -1599,7 +1599,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
|||
startInfo.MaxWorkerThreads = maxThreads;
|
||||
startInfo.MinWorkerThreads = minThreads;
|
||||
startInfo.ThreadPriority = threadPriority;;
|
||||
startInfo.StackSize = stackSize;
|
||||
startInfo.MaxStackSize = stackSize;
|
||||
startInfo.StartSuspended = true;
|
||||
|
||||
m_ThreadPool = new SmartThreadPool(startInfo);
|
||||
|
|
|
@ -52,16 +52,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine
|
|||
return wr.Cancel();
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
public bool Abort()
|
||||
{
|
||||
wr.Abort();
|
||||
return wr.Cancel(true);
|
||||
}
|
||||
|
||||
public bool Wait(int t)
|
||||
{
|
||||
// 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
|
||||
// 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).
|
||||
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.Diagnostics;
|
||||
using System.Threading;
|
||||
|
@ -6,9 +9,9 @@ using System.Web;
|
|||
using System.Runtime.Remoting.Messaging;
|
||||
|
||||
|
||||
namespace Amib.Threading
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
#region CallerThreadContext class
|
||||
#region CallerThreadContext class
|
||||
|
||||
/// <summary>
|
||||
/// This class stores the caller call context in order to restore
|
||||
|
@ -16,13 +19,13 @@ namespace Amib.Threading
|
|||
/// </summary>
|
||||
internal class CallerThreadContext
|
||||
{
|
||||
#region Prepare reflection information
|
||||
#region Prepare reflection information
|
||||
|
||||
// Cached type information.
|
||||
private static MethodInfo getLogicalCallContextMethodInfo =
|
||||
private static readonly MethodInfo getLogicalCallContextMethodInfo =
|
||||
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);
|
||||
|
||||
private static string HttpContextSlotName = GetHttpContextSlotName();
|
||||
|
@ -31,18 +34,20 @@ namespace Amib.Threading
|
|||
{
|
||||
FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
if( fi != null )
|
||||
return (string)fi.GetValue(null);
|
||||
else // Use the default "HttpContext" slot name
|
||||
if (fi != null)
|
||||
{
|
||||
return (string) fi.GetValue(null);
|
||||
}
|
||||
|
||||
return "HttpContext";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private fields
|
||||
#region Private fields
|
||||
|
||||
private HttpContext _httpContext = null;
|
||||
private LogicalCallContext _callContext = null;
|
||||
private HttpContext _httpContext;
|
||||
private LogicalCallContext _callContext;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -122,102 +127,12 @@ namespace Amib.Threading
|
|||
// Restore HttpContext
|
||||
if (callerThreadContext._httpContext != null)
|
||||
{
|
||||
CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
|
||||
HttpContext.Current = callerThreadContext._httpContext;
|
||||
//CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// 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
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
#if !(_WINDOWS_CE)
|
||||
using System.Runtime.Serialization;
|
||||
#endif
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
#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>
|
||||
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class WorkItemCancelException : ApplicationException
|
||||
public sealed partial class WorkItemCancelException
|
||||
{
|
||||
public WorkItemCancelException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemCancelException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemCancelException(string message, Exception e) : base(message, e)
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemCancelException(SerializationInfo si, StreamingContext sc) : base(si, sc)
|
||||
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
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class WorkItemTimeoutException : ApplicationException
|
||||
public sealed partial class WorkItemTimeoutException
|
||||
{
|
||||
public WorkItemTimeoutException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemTimeoutException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemTimeoutException(string message, Exception e) : base(message, e)
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) : base(si, sc)
|
||||
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
|
||||
/// </summary>
|
||||
[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)
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemResultException(string message, Exception e) : base(message, e)
|
||||
{
|
||||
}
|
||||
|
||||
public WorkItemResultException(SerializationInfo si, StreamingContext sc) : base(si, sc)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// Ami Bar
|
||||
// amibar@gmail.com
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -20,16 +17,39 @@ namespace Amib.Threading
|
|||
/// <param name="wir">The work item result object</param>
|
||||
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>
|
||||
/// A delegate to call when a WorkItemsGroup becomes idle
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param>
|
||||
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
|
||||
|
||||
#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
|
||||
{
|
||||
Lowest,
|
||||
|
@ -41,19 +61,11 @@ namespace Amib.Threading
|
|||
|
||||
#endregion
|
||||
|
||||
#region IHasWorkItemPriority interface
|
||||
|
||||
public interface IHasWorkItemPriority
|
||||
{
|
||||
WorkItemPriority WorkItemPriority { get; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IWorkItemsGroup interface
|
||||
|
||||
/// <summary>
|
||||
/// IWorkItemsGroup interface
|
||||
/// Created by SmartThreadPool.CreateWorkItemsGroup()
|
||||
/// </summary>
|
||||
public interface IWorkItemsGroup
|
||||
{
|
||||
|
@ -62,27 +74,293 @@ namespace Amib.Threading
|
|||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback);
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
|
||||
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
|
||||
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);
|
||||
/// <summary>
|
||||
/// Get/Set the maximum number of workitem that execute cocurrency on the thread pool
|
||||
/// </summary>
|
||||
int Concurrency { get; set; }
|
||||
|
||||
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
|
||||
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
|
||||
/// <summary>
|
||||
/// 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();
|
||||
|
||||
/// <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);
|
||||
|
||||
/// <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);
|
||||
|
||||
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;
|
||||
|
||||
void Cancel();
|
||||
void Start();
|
||||
#region QueueWorkItem
|
||||
|
||||
/// <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
|
||||
|
@ -92,9 +370,24 @@ namespace Amib.Threading
|
|||
[Flags]
|
||||
public enum CallToPostExecute
|
||||
{
|
||||
/// <summary>
|
||||
/// Never call to the PostExecute call back
|
||||
/// </summary>
|
||||
Never = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// Call to the PostExecute only when the work item is cancelled
|
||||
/// </summary>
|
||||
WhenWorkItemCanceled = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Call to the PostExecute only when the work item is not cancelled
|
||||
/// </summary>
|
||||
WhenWorkItemNotCanceled = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// Always call to the PostExecute
|
||||
/// </summary>
|
||||
Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
|
||||
}
|
||||
|
||||
|
@ -103,16 +396,43 @@ namespace Amib.Threading
|
|||
#region IWorkItemResult interface
|
||||
|
||||
/// <summary>
|
||||
/// IWorkItemResult interface
|
||||
/// The common interface of IWorkItemResult and IWorkItemResult<T>
|
||||
/// </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>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits.
|
||||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
object GetResult();
|
||||
TResult GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
|
@ -120,7 +440,7 @@ namespace Amib.Threading
|
|||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
object GetResult(
|
||||
TResult GetResult(
|
||||
int millisecondsTimeout,
|
||||
bool exitContext);
|
||||
|
||||
|
@ -130,12 +450,10 @@ namespace Amib.Threading
|
|||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
object GetResult(
|
||||
TResult GetResult(
|
||||
TimeSpan timeout,
|
||||
bool exitContext);
|
||||
|
||||
void Abort();
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
|
||||
|
@ -148,7 +466,7 @@ namespace Amib.Threading
|
|||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
/// On cancel throws WorkItemCancelException
|
||||
object GetResult(
|
||||
TResult GetResult(
|
||||
int millisecondsTimeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle);
|
||||
|
@ -160,7 +478,7 @@ namespace Amib.Threading
|
|||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
/// On cancel throws WorkItemCancelException
|
||||
object GetResult(
|
||||
TResult GetResult(
|
||||
TimeSpan timeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle);
|
||||
|
@ -171,16 +489,18 @@ namespace Amib.Threading
|
|||
/// </summary>
|
||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||
/// <returns>The result of the work item</returns>
|
||||
object GetResult(out Exception e);
|
||||
TResult GetResult(out Exception e);
|
||||
|
||||
/// <summary>
|
||||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout.
|
||||
/// </summary>
|
||||
/// <param name="millisecondsTimeout"></param>
|
||||
/// <param name="exitContext"></param>
|
||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
object GetResult(
|
||||
TResult GetResult(
|
||||
int millisecondsTimeout,
|
||||
bool exitContext,
|
||||
out Exception e);
|
||||
|
@ -189,10 +509,12 @@ namespace Amib.Threading
|
|||
/// Get the result of the work item.
|
||||
/// If the work item didn't run yet then the caller waits until timeout.
|
||||
/// </summary>
|
||||
/// <param name="exitContext"></param>
|
||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
object GetResult(
|
||||
TResult GetResult(
|
||||
TimeSpan timeout,
|
||||
bool exitContext,
|
||||
out Exception e);
|
||||
|
@ -210,7 +532,7 @@ namespace Amib.Threading
|
|||
/// <returns>The result of the work item</returns>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
/// On cancel throws WorkItemCancelException
|
||||
object GetResult(
|
||||
TResult GetResult(
|
||||
int millisecondsTimeout,
|
||||
bool exitContext,
|
||||
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.
|
||||
/// </summary>
|
||||
/// <returns>The result of the work item</returns>
|
||||
/// <param name="cancelWaitHandle"></param>
|
||||
/// <param name="e">Filled with the exception if one was thrown</param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="exitContext"></param>
|
||||
/// On timeout throws WorkItemTimeoutException
|
||||
/// On cancel throws WorkItemCancelException
|
||||
object GetResult(
|
||||
TResult GetResult(
|
||||
TimeSpan timeout,
|
||||
bool exitContext,
|
||||
WaitHandle cancelWaitHandle,
|
||||
|
@ -241,16 +566,30 @@ namespace Amib.Threading
|
|||
bool IsCanceled { get; }
|
||||
|
||||
/// <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>
|
||||
object State { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Cancel the work item if it didn't start running yet.
|
||||
/// Same as Cancel(false).
|
||||
/// </summary>
|
||||
/// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
|
||||
bool Cancel();
|
||||
|
||||
/// <summary>
|
||||
/// Cancel the work item execution.
|
||||
/// If the work item is in the queue then it won't execute
|
||||
/// If the work item is completed, it will remain completed
|
||||
/// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled
|
||||
/// property to check if the work item has been cancelled. If the abortExecution is set to true then
|
||||
/// the Smart Thread Pool will send an AbortException to the running thread to stop the execution
|
||||
/// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException.
|
||||
/// If the work item is already cancelled it will remain cancelled
|
||||
/// </summary>
|
||||
/// <param name="abortExecution">When true send an AbortException to the executing thread.</param>
|
||||
/// <returns>Returns true if the work item was not completed, otherwise false.</returns>
|
||||
bool Cancel(bool abortExecution);
|
||||
|
||||
/// <summary>
|
||||
/// Get the work item's priority
|
||||
/// </summary>
|
||||
|
@ -259,7 +598,7 @@ namespace Amib.Threading
|
|||
/// <summary>
|
||||
/// Return the result, same as GetResult()
|
||||
/// </summary>
|
||||
object Result { get; }
|
||||
TResult Result { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the exception if occured otherwise returns null.
|
||||
|
@ -267,5 +606,23 @@ namespace Amib.Threading
|
|||
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
|
||||
}
|
||||
|
|
|
@ -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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
|
@ -25,17 +23,17 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Work items queues. There is one for each type of priority
|
||||
/// </summary>
|
||||
private Queue [] _queues = new Queue[_queuesCount];
|
||||
private readonly LinkedList<IHasWorkItemPriority>[] _queues = new LinkedList<IHasWorkItemPriority>[_queuesCount];
|
||||
|
||||
/// <summary>
|
||||
/// The total number of work items within the queues
|
||||
/// </summary>
|
||||
private int _workItemsCount = 0;
|
||||
private int _workItemsCount;
|
||||
|
||||
/// <summary>
|
||||
/// Use with IEnumerable interface
|
||||
/// </summary>
|
||||
private int _version = 0;
|
||||
private int _version;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -45,7 +43,7 @@ namespace Amib.Threading.Internal
|
|||
{
|
||||
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 < _queuesCount);
|
||||
|
||||
_queues[queueIndex].Enqueue(workItem);
|
||||
_queues[queueIndex].AddLast(workItem);
|
||||
++_workItemsCount;
|
||||
++_version;
|
||||
}
|
||||
|
@ -82,7 +80,8 @@ namespace Amib.Threading.Internal
|
|||
{
|
||||
int queueIndex = GetNextNonEmptyQueue(-1);
|
||||
Debug.Assert(queueIndex >= 0);
|
||||
workItem = _queues[queueIndex].Dequeue() as IHasWorkItemPriority;
|
||||
workItem = _queues[queueIndex].First.Value;
|
||||
_queues[queueIndex].RemoveFirst();
|
||||
Debug.Assert(null != workItem);
|
||||
--_workItemsCount;
|
||||
++_version;
|
||||
|
@ -128,7 +127,7 @@ namespace Amib.Threading.Internal
|
|||
{
|
||||
if (_workItemsCount > 0)
|
||||
{
|
||||
foreach(Queue queue in _queues)
|
||||
foreach(LinkedList<IHasWorkItemPriority> queue in _queues)
|
||||
{
|
||||
queue.Clear();
|
||||
}
|
||||
|
@ -159,7 +158,7 @@ namespace Amib.Threading.Internal
|
|||
/// </summary>
|
||||
private class PriorityQueueEnumerator : IEnumerator
|
||||
{
|
||||
private PriorityQueue _priorityQueue;
|
||||
private readonly PriorityQueue _priorityQueue;
|
||||
private int _version;
|
||||
private int _queueIndex;
|
||||
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.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
public interface ISTPPerformanceCountersReader
|
||||
{
|
||||
long InUseThreads { get; }
|
||||
long ActiveThreads { get; }
|
||||
long WorkItemsQueued { get; }
|
||||
long WorkItemsProcessed { get; }
|
||||
}
|
||||
}
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
internal interface ISTPInstancePerformanceCounters : IDisposable
|
||||
{
|
||||
void Close();
|
||||
void SampleThreads(long activeThreads, long inUseThreads);
|
||||
void SampleWorkItems(long workItemsQueued, long workItemsProcessed);
|
||||
void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime);
|
||||
void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime);
|
||||
}
|
||||
#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
|
||||
internal enum STPPerformanceCounterType
|
||||
{
|
||||
// Fields
|
||||
|
@ -37,7 +59,7 @@ namespace Amib.Threading.Internal
|
|||
internal class STPPerformanceCounter
|
||||
{
|
||||
// Fields
|
||||
private PerformanceCounterType _pcType;
|
||||
private readonly PerformanceCounterType _pcType;
|
||||
protected string _counterHelp;
|
||||
protected string _counterName;
|
||||
|
||||
|
@ -47,9 +69,9 @@ namespace Amib.Threading.Internal
|
|||
string counterHelp,
|
||||
PerformanceCounterType pcType)
|
||||
{
|
||||
this._counterName = counterName;
|
||||
this._counterHelp = counterHelp;
|
||||
this._pcType = pcType;
|
||||
_counterName = counterName;
|
||||
_counterHelp = counterHelp;
|
||||
_pcType = pcType;
|
||||
}
|
||||
|
||||
public void AddCounterToCollection(CounterCreationDataCollection counterData)
|
||||
|
@ -76,7 +98,7 @@ namespace Amib.Threading.Internal
|
|||
{
|
||||
// Fields
|
||||
internal STPPerformanceCounter[] _stpPerformanceCounters;
|
||||
private static STPPerformanceCounters _instance;
|
||||
private static readonly STPPerformanceCounters _instance;
|
||||
internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
|
||||
internal const string _stpCategoryName = "SmartThreadPool";
|
||||
|
||||
|
@ -127,19 +149,12 @@ namespace Amib.Threading.Internal
|
|||
_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(
|
||||
_stpCategoryName,
|
||||
_stpCategoryHelp,
|
||||
//PerformanceCounterCategoryType.MultiInstance,
|
||||
PerformanceCounterCategoryType.MultiInstance,
|
||||
counters);
|
||||
#pragma warning restore 0618
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,16 +171,18 @@ namespace Amib.Threading.Internal
|
|||
internal class STPInstancePerformanceCounter : IDisposable
|
||||
{
|
||||
// Fields
|
||||
private bool _isDisposed;
|
||||
private PerformanceCounter _pcs;
|
||||
|
||||
// Methods
|
||||
protected STPInstancePerformanceCounter()
|
||||
{
|
||||
_isDisposed = false;
|
||||
}
|
||||
|
||||
public STPInstancePerformanceCounter(
|
||||
string instance,
|
||||
STPPerformanceCounterType spcType)
|
||||
STPPerformanceCounterType spcType) : this()
|
||||
{
|
||||
STPPerformanceCounters counters = STPPerformanceCounters.Instance;
|
||||
_pcs = new PerformanceCounter(
|
||||
|
@ -176,10 +193,6 @@ namespace Amib.Threading.Internal
|
|||
_pcs.RawValue = _pcs.RawValue;
|
||||
}
|
||||
|
||||
~STPInstancePerformanceCounter()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
|
@ -192,9 +205,20 @@ namespace Amib.Threading.Internal
|
|||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
public virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Close();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
_isDisposed = true;
|
||||
}
|
||||
|
||||
public virtual void Increment()
|
||||
|
@ -216,27 +240,19 @@ namespace Amib.Threading.Internal
|
|||
internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter
|
||||
{
|
||||
// Methods
|
||||
public STPInstanceNullPerformanceCounter() {}
|
||||
public override void Increment() {}
|
||||
public override void IncrementBy(long value) {}
|
||||
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
|
||||
private STPInstancePerformanceCounter[] _pcs;
|
||||
private static STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
|
||||
private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
|
||||
|
||||
// Methods
|
||||
static STPInstancePerformanceCounters()
|
||||
|
@ -246,8 +262,13 @@ namespace Amib.Threading.Internal
|
|||
|
||||
public STPInstancePerformanceCounters(string instance)
|
||||
{
|
||||
_isDisposed = false;
|
||||
_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++)
|
||||
{
|
||||
if (instance != null)
|
||||
|
@ -272,22 +293,28 @@ namespace Amib.Threading.Internal
|
|||
{
|
||||
if (null != _pcs[i])
|
||||
{
|
||||
_pcs[i].Close();
|
||||
_pcs[i].Dispose();
|
||||
}
|
||||
}
|
||||
_pcs = null;
|
||||
}
|
||||
}
|
||||
|
||||
~STPInstancePerformanceCounters()
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
public virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
_isDisposed = true;
|
||||
}
|
||||
|
||||
private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
|
||||
|
@ -327,21 +354,17 @@ namespace Amib.Threading.Internal
|
|||
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable
|
||||
internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
|
||||
{
|
||||
static NullSTPInstancePerformanceCounters()
|
||||
{
|
||||
}
|
||||
|
||||
private static NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(null);
|
||||
private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters();
|
||||
|
||||
public static NullSTPInstancePerformanceCounters Instance
|
||||
{
|
||||
get { return _instance; }
|
||||
}
|
||||
|
||||
public NullSTPInstancePerformanceCounters(string instance) {}
|
||||
public void Close() {}
|
||||
public void Dispose() {}
|
||||
|
||||
|
@ -349,6 +372,77 @@ namespace Amib.Threading.Internal
|
|||
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
|
||||
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
|
||||
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {}
|
||||
public long InUseThreads
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public long ActiveThreads
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public long WorkItemsQueued
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public long WorkItemsProcessed
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
}
|
||||
|
||||
internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader
|
||||
{
|
||||
public void Close() { }
|
||||
public void Dispose() { }
|
||||
|
||||
private long _activeThreads;
|
||||
private long _inUseThreads;
|
||||
private long _workItemsQueued;
|
||||
private long _workItemsProcessed;
|
||||
|
||||
public long InUseThreads
|
||||
{
|
||||
get { return _inUseThreads; }
|
||||
}
|
||||
|
||||
public long ActiveThreads
|
||||
{
|
||||
get { return _activeThreads; }
|
||||
}
|
||||
|
||||
public long WorkItemsQueued
|
||||
{
|
||||
get { return _workItemsQueued; }
|
||||
}
|
||||
|
||||
public long WorkItemsProcessed
|
||||
{
|
||||
get { return _workItemsProcessed; }
|
||||
}
|
||||
|
||||
public void SampleThreads(long activeThreads, long inUseThreads)
|
||||
{
|
||||
_activeThreads = activeThreads;
|
||||
_inUseThreads = inUseThreads;
|
||||
}
|
||||
|
||||
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
|
||||
{
|
||||
_workItemsQueued = workItemsQueued;
|
||||
_workItemsProcessed = workItemsProcessed;
|
||||
}
|
||||
|
||||
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
|
||||
{
|
||||
// Not supported
|
||||
}
|
||||
|
||||
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
|
||||
{
|
||||
// Not supported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
// Ami Bar
|
||||
// amibar@gmail.com
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading
|
||||
|
@ -10,104 +8,205 @@ namespace Amib.Threading
|
|||
/// </summary>
|
||||
public class STPStartInfo : WIGStartInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Idle timeout in milliseconds.
|
||||
/// If a thread is idle for _idleTimeout milliseconds then
|
||||
/// it may quit.
|
||||
/// </summary>
|
||||
private int _idleTimeout;
|
||||
private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
|
||||
private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
|
||||
private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
|
||||
#if !(WINDOWS_PHONE)
|
||||
private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority;
|
||||
#endif
|
||||
private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
|
||||
private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground;
|
||||
private bool _enableLocalPerformanceCounters;
|
||||
private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName;
|
||||
private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize;
|
||||
|
||||
/// <summary>
|
||||
/// 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()
|
||||
public STPStartInfo()
|
||||
{
|
||||
_performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
|
||||
#if !(WINDOWS_PHONE)
|
||||
_threadPriority = SmartThreadPool.DefaultThreadPriority;
|
||||
#endif
|
||||
_maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
|
||||
_idleTimeout = SmartThreadPool.DefaultIdleTimeout;
|
||||
_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;
|
||||
_minWorkerThreads = stpStartInfo._minWorkerThreads;
|
||||
_maxWorkerThreads = stpStartInfo._maxWorkerThreads;
|
||||
_threadPriority = stpStartInfo._threadPriority;
|
||||
_idleTimeout = stpStartInfo.IdleTimeout;
|
||||
_minWorkerThreads = stpStartInfo.MinWorkerThreads;
|
||||
_maxWorkerThreads = stpStartInfo.MaxWorkerThreads;
|
||||
#if !(WINDOWS_PHONE)
|
||||
_threadPriority = stpStartInfo.ThreadPriority;
|
||||
#endif
|
||||
_performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName;
|
||||
_enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters;
|
||||
_threadPoolName = stpStartInfo._threadPoolName;
|
||||
_pcInstanceName = stpStartInfo._pcInstanceName;
|
||||
_stackSize = stpStartInfo._stackSize;
|
||||
_areThreadsBackground = stpStartInfo.AreThreadsBackground;
|
||||
#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; }
|
||||
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; }
|
||||
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; }
|
||||
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; }
|
||||
set { _threadPriority = value; }
|
||||
}
|
||||
|
||||
public virtual string ThreadPoolName
|
||||
set
|
||||
{
|
||||
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; }
|
||||
set { _threadPoolName = value; }
|
||||
}
|
||||
|
||||
|
||||
public string PerformanceCounterInstanceName
|
||||
set
|
||||
{
|
||||
get { return _pcInstanceName; }
|
||||
set { _pcInstanceName = value; }
|
||||
ThrowIfReadOnly ();
|
||||
_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; }
|
||||
set { _stackSize = value; }
|
||||
get { return _performanceCounterInstanceName; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_performanceCounterInstanceName = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable/Disable the local performance counter.
|
||||
/// This enables the user to get some performance information about the SmartThreadPool
|
||||
/// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.)
|
||||
/// The default is false.
|
||||
/// </summary>
|
||||
public virtual bool EnableLocalPerformanceCounters
|
||||
{
|
||||
get { return _enableLocalPerformanceCounters; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_enableLocalPerformanceCounters = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set backgroundness of thread in thread pool.
|
||||
/// </summary>
|
||||
public virtual bool AreThreadsBackground
|
||||
{
|
||||
get { return _areThreadsBackground; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly ();
|
||||
_areThreadsBackground = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a readonly version of this STPStartInfo.
|
||||
/// </summary>
|
||||
/// <returns>Returns a readonly reference to this STPStartInfo</returns>
|
||||
public new STPStartInfo AsReadOnly()
|
||||
{
|
||||
return new STPStartInfo(this) { _readOnly = true };
|
||||
}
|
||||
|
||||
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
|
||||
private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState;
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the apartment state of threads in the thread pool
|
||||
/// </summary>
|
||||
public ApartmentState ApartmentState
|
||||
{
|
||||
get { return _apartmentState; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
_apartmentState = value;
|
||||
}
|
||||
}
|
||||
|
||||
#if !(_SILVERLIGHT) && !(WINDOWS_PHONE)
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the max stack size of threads in the thread pool
|
||||
/// </summary>
|
||||
public int? MaxStackSize
|
||||
{
|
||||
get { return _maxStackSize; }
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
if (value.HasValue && value.Value < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value", "Value must be greater than 0.");
|
||||
}
|
||||
_maxStackSize = value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
// amibar@gmail.com
|
||||
using System;
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
|
@ -8,92 +7,165 @@ namespace Amib.Threading
|
|||
/// </summary>
|
||||
public class WIGStartInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Use the caller's security context
|
||||
/// </summary>
|
||||
private bool _useCallerCallContext;
|
||||
|
||||
/// <summary>
|
||||
/// Use the caller's HTTP 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>
|
||||
/// Indicate the WorkItemsGroup to suspend the handling of the work items
|
||||
/// until the Start() method is called.
|
||||
/// </summary>
|
||||
private bool _startSuspended;
|
||||
private WorkItemPriority _workItemPriority;
|
||||
private bool _fillStateWithArgs;
|
||||
|
||||
protected bool _readOnly;
|
||||
|
||||
public WIGStartInfo()
|
||||
{
|
||||
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
||||
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
||||
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
||||
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
||||
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
||||
_fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs;
|
||||
_workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
|
||||
_startSuspended = SmartThreadPool.DefaultStartSuspended;
|
||||
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
||||
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
||||
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
||||
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
||||
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
||||
}
|
||||
|
||||
public WIGStartInfo(WIGStartInfo wigStartInfo)
|
||||
{
|
||||
_useCallerCallContext = wigStartInfo._useCallerCallContext;
|
||||
_useCallerHttpContext = wigStartInfo._useCallerHttpContext;
|
||||
_disposeOfStateObjects = wigStartInfo._disposeOfStateObjects;
|
||||
_callToPostExecute = wigStartInfo._callToPostExecute;
|
||||
_postExecuteWorkItemCallback = wigStartInfo._postExecuteWorkItemCallback;
|
||||
_startSuspended = wigStartInfo._startSuspended;
|
||||
_useCallerCallContext = wigStartInfo.UseCallerCallContext;
|
||||
_useCallerHttpContext = wigStartInfo.UseCallerHttpContext;
|
||||
_disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
_callToPostExecute = wigStartInfo.CallToPostExecute;
|
||||
_postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
||||
_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; }
|
||||
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; }
|
||||
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; }
|
||||
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; }
|
||||
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; }
|
||||
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; }
|
||||
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
|
||||
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,3 @@
|
|||
// Ami Bar
|
||||
// amibar@gmail.com
|
||||
|
||||
using System;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
|
@ -12,6 +9,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <returns>Returns a work item</returns>
|
||||
|
@ -26,6 +24,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="workItemPriority">The priority of the work item</param>
|
||||
|
@ -42,6 +41,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="workItemInfo">Work item info</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
|
@ -63,6 +63,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
|
@ -83,6 +84,7 @@ namespace Amib.Threading.Internal
|
|||
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
|
||||
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||
|
||||
WorkItem workItem = new WorkItem(
|
||||
workItemsGroup,
|
||||
|
@ -95,6 +97,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
|
@ -131,6 +134,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="workItemInfo">Work item information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
|
@ -160,6 +164,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
|
@ -185,6 +190,7 @@ namespace Amib.Threading.Internal
|
|||
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
|
||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||
|
||||
WorkItem workItem = new WorkItem(
|
||||
workItemsGroup,
|
||||
|
@ -198,6 +204,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
|
@ -239,6 +246,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
|
@ -266,6 +274,7 @@ namespace Amib.Threading.Internal
|
|||
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
|
||||
workItemInfo.CallToPostExecute = callToPostExecute;
|
||||
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
|
||||
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
|
||||
|
||||
WorkItem workItem = new WorkItem(
|
||||
workItemsGroup,
|
||||
|
@ -279,6 +288,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Create a new work item
|
||||
/// </summary>
|
||||
/// <param name="workItemsGroup">The work items group</param>
|
||||
/// <param name="wigStartInfo">Work item group start information</param>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <param name="state">
|
||||
|
@ -322,7 +332,7 @@ namespace Amib.Threading.Internal
|
|||
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// Ami Bar
|
||||
// amibar@gmail.com
|
||||
|
||||
namespace Amib.Threading
|
||||
{
|
||||
#region WorkItemInfo class
|
||||
|
@ -10,92 +7,62 @@ namespace Amib.Threading
|
|||
/// </summary>
|
||||
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()
|
||||
{
|
||||
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
||||
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
||||
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
||||
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
||||
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
||||
_workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
|
||||
UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
|
||||
UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
|
||||
DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
|
||||
CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
|
||||
PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
|
||||
WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority;
|
||||
}
|
||||
|
||||
public WorkItemInfo(WorkItemInfo workItemInfo)
|
||||
{
|
||||
_useCallerCallContext = workItemInfo._useCallerCallContext;
|
||||
_useCallerHttpContext = workItemInfo._useCallerHttpContext;
|
||||
_disposeOfStateObjects = workItemInfo._disposeOfStateObjects;
|
||||
_callToPostExecute = workItemInfo._callToPostExecute;
|
||||
_postExecuteWorkItemCallback = workItemInfo._postExecuteWorkItemCallback;
|
||||
_workItemPriority = workItemInfo._workItemPriority;
|
||||
UseCallerCallContext = workItemInfo.UseCallerCallContext;
|
||||
UseCallerHttpContext = workItemInfo.UseCallerHttpContext;
|
||||
DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects;
|
||||
CallToPostExecute = workItemInfo.CallToPostExecute;
|
||||
PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback;
|
||||
WorkItemPriority = workItemInfo.WorkItemPriority;
|
||||
Timeout = workItemInfo.Timeout;
|
||||
}
|
||||
|
||||
public bool UseCallerCallContext
|
||||
{
|
||||
get { return _useCallerCallContext; }
|
||||
set { _useCallerCallContext = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Get/Set if to use the caller's security context
|
||||
/// </summary>
|
||||
public bool UseCallerCallContext { get; set; }
|
||||
|
||||
public bool UseCallerHttpContext
|
||||
{
|
||||
get { return _useCallerHttpContext; }
|
||||
set { _useCallerHttpContext = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Get/Set if to use the caller's HTTP context
|
||||
/// </summary>
|
||||
public bool UseCallerHttpContext { get; set; }
|
||||
|
||||
public bool DisposeOfStateObjects
|
||||
{
|
||||
get { return _disposeOfStateObjects; }
|
||||
set { _disposeOfStateObjects = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Get/Set if to dispose of the state object of a work item
|
||||
/// </summary>
|
||||
public bool DisposeOfStateObjects { get; set; }
|
||||
|
||||
public CallToPostExecute CallToPostExecute
|
||||
{
|
||||
get { return _callToPostExecute; }
|
||||
set { _callToPostExecute = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Get/Set the run the post execute options
|
||||
/// </summary>
|
||||
public CallToPostExecute CallToPostExecute { get; set; }
|
||||
|
||||
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
|
||||
{
|
||||
get { return _postExecuteWorkItemCallback; }
|
||||
set { _postExecuteWorkItemCallback = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Get/Set the post execute callback
|
||||
/// </summary>
|
||||
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; }
|
||||
|
||||
public WorkItemPriority WorkItemPriority
|
||||
{
|
||||
get { return _workItemPriority; }
|
||||
set { _workItemPriority = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Get/Set the work item's priority
|
||||
/// </summary>
|
||||
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
|
||||
|
|
|
@ -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.Threading;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
@ -8,33 +5,34 @@ using System.Diagnostics;
|
|||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
|
||||
#region WorkItemsGroup class
|
||||
|
||||
/// <summary>
|
||||
/// Summary description for WorkItemsGroup.
|
||||
/// </summary>
|
||||
public class WorkItemsGroup : IWorkItemsGroup
|
||||
public class WorkItemsGroup : WorkItemsGroupBase
|
||||
{
|
||||
#region Private members
|
||||
|
||||
private object _lock = new object();
|
||||
/// <summary>
|
||||
/// Contains the name of this instance of SmartThreadPool.
|
||||
/// Can be changed by the user.
|
||||
/// </summary>
|
||||
private string _name = "WorkItemsGroup";
|
||||
private readonly object _lock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the SmartThreadPool instance that created this
|
||||
/// WorkItemsGroup.
|
||||
/// </summary>
|
||||
private SmartThreadPool _stp;
|
||||
private readonly SmartThreadPool _stp;
|
||||
|
||||
/// <summary>
|
||||
/// The OnIdle event
|
||||
/// </summary>
|
||||
private event WorkItemsGroupIdleHandler _onIdle;
|
||||
|
||||
/// <summary>
|
||||
/// A flag to indicate if the Work Items Group is now suspended.
|
||||
/// </summary>
|
||||
private bool _isSuspended;
|
||||
|
||||
/// <summary>
|
||||
/// Defines how many work items of this WorkItemsGroup can run at once.
|
||||
/// </summary>
|
||||
|
@ -44,7 +42,7 @@ namespace Amib.Threading.Internal
|
|||
/// Priority queue to hold work items before they are passed
|
||||
/// to the SmartThreadPool.
|
||||
/// </summary>
|
||||
private PriorityQueue _workItemsQueue;
|
||||
private readonly PriorityQueue _workItemsQueue;
|
||||
|
||||
/// <summary>
|
||||
/// Indicate how many work items are waiting in the SmartThreadPool
|
||||
|
@ -63,12 +61,13 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// WorkItemsGroup start information
|
||||
/// </summary>
|
||||
private WIGStartInfo _workItemsGroupStartInfo;
|
||||
private readonly WIGStartInfo _workItemsGroupStartInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Signaled when all of the WorkItemsGroup's work item completed.
|
||||
/// </summary>
|
||||
private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
|
||||
//private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
|
||||
private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
|
||||
|
||||
/// <summary>
|
||||
/// A common object for all the work items that this work items group
|
||||
|
@ -87,286 +86,118 @@ namespace Amib.Threading.Internal
|
|||
{
|
||||
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;
|
||||
_concurrency = concurrency;
|
||||
_workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo);
|
||||
_workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly();
|
||||
_workItemsQueue = new PriorityQueue();
|
||||
Name = "WorkItemsGroup";
|
||||
|
||||
// The _workItemsInStpQueue gets the number of currently executing work items,
|
||||
// because once a work item is executing, it cannot be cancelled.
|
||||
_workItemsInStpQueue = _workItemsExecutingInStp;
|
||||
|
||||
_isSuspended = _workItemsGroupStartInfo.StartSuspended;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IWorkItemsGroup implementation
|
||||
#region WorkItemsGroupBase Overrides
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the name of the SmartThreadPool instance
|
||||
/// </summary>
|
||||
public string Name
|
||||
public override int Concurrency
|
||||
{
|
||||
get
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
get { return _concurrency; }
|
||||
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>
|
||||
/// Queue a work item
|
||||
/// WorkItemsGroup start information
|
||||
/// </summary>
|
||||
/// <param name="callback">A callback to execute</param>
|
||||
/// <returns>Returns a work item result</returns>
|
||||
public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
|
||||
public override WIGStartInfo WIGStartInfo
|
||||
{
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback);
|
||||
EnqueueToSTPNextWorkItem(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
get { return _workItemsGroupStartInfo; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a work item
|
||||
/// Start the Work Items Group if it was started suspended
|
||||
/// </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)
|
||||
public override void Start()
|
||||
{
|
||||
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, workItemPriority);
|
||||
EnqueueToSTPNextWorkItem(workItem);
|
||||
return workItem.GetWorkItemResult();
|
||||
// If the Work Items Group already started then quit
|
||||
if (!_isSuspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_isSuspended = false;
|
||||
|
||||
EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency));
|
||||
}
|
||||
|
||||
/// <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)
|
||||
public override void Cancel(bool abortExecution)
|
||||
{
|
||||
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)
|
||||
{
|
||||
_canceledWorkItemsGroup.IsCanceled = true;
|
||||
_workItemsQueue.Clear();
|
||||
_workItemsInStpQueue = 0;
|
||||
_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)
|
||||
{
|
||||
if (!_workItemsGroupStartInfo.StartSuspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_workItemsGroupStartInfo.StartSuspended = false;
|
||||
SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
|
||||
return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
|
||||
}
|
||||
|
||||
for(int i = 0; i < _concurrency; ++i)
|
||||
public override event WorkItemsGroupIdleHandler OnIdle
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(null, false);
|
||||
}
|
||||
add { _onIdle += value; }
|
||||
remove { _onIdle -= value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -375,22 +206,24 @@ namespace Amib.Threading.Internal
|
|||
|
||||
private void RegisterToWorkItemCompletion(IWorkItemResult wir)
|
||||
{
|
||||
IInternalWorkItemResult iwir = wir as IInternalWorkItemResult;
|
||||
iwir.OnWorkItemStarted += new WorkItemStateCallback(OnWorkItemStartedCallback);
|
||||
iwir.OnWorkItemCompleted += new WorkItemStateCallback(OnWorkItemCompletedCallback);
|
||||
IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir;
|
||||
iwir.OnWorkItemStarted += OnWorkItemStartedCallback;
|
||||
iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback;
|
||||
}
|
||||
|
||||
public void OnSTPIsStarting()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (_workItemsGroupStartInfo.StartSuspended)
|
||||
if (_isSuspended)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
@ -417,8 +250,7 @@ namespace Amib.Threading.Internal
|
|||
{
|
||||
eh(this);
|
||||
}
|
||||
// Ignore exceptions
|
||||
catch{}
|
||||
catch { } // Suppress exceptions
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -435,6 +267,11 @@ namespace Amib.Threading.Internal
|
|||
EnqueueToSTPNextWorkItem(null, true);
|
||||
}
|
||||
|
||||
internal override void Enqueue(WorkItem workItem)
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(workItem);
|
||||
}
|
||||
|
||||
private void EnqueueToSTPNextWorkItem(WorkItem workItem)
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(workItem, false);
|
||||
|
@ -475,7 +312,7 @@ namespace Amib.Threading.Internal
|
|||
(0 == _workItemsInStpQueue))
|
||||
{
|
||||
_stp.RegisterWorkItemsGroup(this);
|
||||
Trace.WriteLine("WorkItemsGroup " + Name + " is NOT idle");
|
||||
IsIdle = false;
|
||||
_isIdleWaitHandle.Reset();
|
||||
}
|
||||
}
|
||||
|
@ -486,19 +323,31 @@ namespace Amib.Threading.Internal
|
|||
if (0 == _workItemsInStpQueue)
|
||||
{
|
||||
_stp.UnregisterWorkItemsGroup(this);
|
||||
Trace.WriteLine("WorkItemsGroup " + Name + " is idle");
|
||||
IsIdle = true;
|
||||
_isIdleWaitHandle.Set();
|
||||
_stp.QueueWorkItem(new WorkItemCallback(this.FireOnIdle));
|
||||
if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0)
|
||||
{
|
||||
_stp.QueueWorkItem(new WorkItemCallback(FireOnIdle));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_workItemsGroupStartInfo.StartSuspended)
|
||||
if (!_isSuspended)
|
||||
{
|
||||
if (_workItemsInStpQueue < _concurrency)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
|
@ -18,7 +16,7 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Waiters queue (implemented as stack).
|
||||
/// </summary>
|
||||
private WaiterEntry _headWaiterEntry = new WaiterEntry();
|
||||
private readonly WaiterEntry _headWaiterEntry = new WaiterEntry();
|
||||
|
||||
/// <summary>
|
||||
/// Waiters count
|
||||
|
@ -28,18 +26,70 @@ namespace Amib.Threading.Internal
|
|||
/// <summary>
|
||||
/// Work items queue
|
||||
/// </summary>
|
||||
private PriorityQueue _workItems = new PriorityQueue();
|
||||
private readonly PriorityQueue _workItems = new PriorityQueue();
|
||||
|
||||
/// <summary>
|
||||
/// Indicate that work items are allowed to be queued
|
||||
/// </summary>
|
||||
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>
|
||||
/// Each thread in the thread pool keeps its own waiter entry.
|
||||
/// </summary>
|
||||
[ThreadStatic]
|
||||
private static WaiterEntry _waiterEntry;
|
||||
private static WaiterEntry CurrentWaiterEntry
|
||||
{
|
||||
#if (WINDOWS_PHONE)
|
||||
get
|
||||
{
|
||||
lock (_waiterEntries)
|
||||
{
|
||||
WaiterEntry waiterEntry;
|
||||
if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry))
|
||||
{
|
||||
return waiterEntry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_waiterEntries)
|
||||
{
|
||||
_waiterEntries[Thread.CurrentThread.ManagedThreadId] = value;
|
||||
}
|
||||
}
|
||||
#elif (_WINDOWS_CE)
|
||||
get
|
||||
{
|
||||
return Thread.GetData(_waiterEntrySlot) as WaiterEntry;
|
||||
}
|
||||
set
|
||||
{
|
||||
Thread.SetData(_waiterEntrySlot, value);
|
||||
}
|
||||
#else
|
||||
get
|
||||
{
|
||||
return _waiterEntry;
|
||||
}
|
||||
set
|
||||
{
|
||||
_waiterEntry = value;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A flag that indicates if the WorkItemsQueue has been disposed.
|
||||
|
@ -57,13 +107,9 @@ namespace Amib.Threading.Internal
|
|||
{
|
||||
get
|
||||
{
|
||||
lock(this)
|
||||
{
|
||||
ValidateNotDisposed();
|
||||
return _workItems.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current number of waiters
|
||||
|
@ -72,13 +118,9 @@ namespace Amib.Threading.Internal
|
|||
{
|
||||
get
|
||||
{
|
||||
lock(this)
|
||||
{
|
||||
ValidateNotDisposed();
|
||||
return _waitersCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
@ -144,22 +186,21 @@ namespace Amib.Threading.Internal
|
|||
int millisecondsTimeout,
|
||||
WaitHandle cancelEvent)
|
||||
{
|
||||
/// This method cause the caller to wait for a work item.
|
||||
/// If there is at least one waiting work item then the
|
||||
/// method returns immidiately with true.
|
||||
///
|
||||
/// If there are no waiting work items then the caller
|
||||
/// is queued between other waiters for a work item to arrive.
|
||||
///
|
||||
/// If a work item didn't come within millisecondsTimeout or
|
||||
/// the user canceled the wait by signaling the cancelEvent
|
||||
/// then the method returns false to indicate that the caller
|
||||
/// didn't get 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
|
||||
// method returns immidiately with it.
|
||||
//
|
||||
// If there are no waiting work items then the caller
|
||||
// is queued between other waiters for a work item to arrive.
|
||||
//
|
||||
// If a work item didn't come within millisecondsTimeout or
|
||||
// the user canceled the wait by signaling the cancelEvent
|
||||
// then the method returns null to indicate that the caller
|
||||
// didn't get a work item.
|
||||
|
||||
WaiterEntry waiterEntry = null;
|
||||
WaiterEntry waiterEntry;
|
||||
WorkItem workItem = null;
|
||||
|
||||
lock(this)
|
||||
lock (this)
|
||||
{
|
||||
ValidateNotDisposed();
|
||||
|
||||
|
@ -169,19 +210,18 @@ namespace Amib.Threading.Internal
|
|||
workItem = _workItems.Dequeue() as WorkItem;
|
||||
return workItem;
|
||||
}
|
||||
|
||||
// No waiting work items ...
|
||||
else
|
||||
{
|
||||
// Get the wait entry for the waiters queue
|
||||
|
||||
// Get the waiter entry for the waiters queue
|
||||
waiterEntry = GetThreadWaiterEntry();
|
||||
|
||||
// Put the waiter with the other waiters
|
||||
PushWaiter(waiterEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare array of wait handle for the WaitHandle.WaitAny()
|
||||
WaitHandle [] waitHandles = new WaitHandle [] {
|
||||
WaitHandle [] waitHandles = new WaitHandle[] {
|
||||
waiterEntry.WaitHandle,
|
||||
cancelEvent };
|
||||
|
||||
|
@ -189,10 +229,10 @@ namespace Amib.Threading.Internal
|
|||
|
||||
// During the wait we are supposes to exit the synchronization
|
||||
// domain. (Placing true as the third argument of the WaitAny())
|
||||
// It just doesn't work, I don't know why, so I have lock(this)
|
||||
// statments insted of one.
|
||||
// It just doesn't work, I don't know why, so I have two lock(this)
|
||||
// statments instead of one.
|
||||
|
||||
int index = WaitHandle.WaitAny(
|
||||
int index = STPEventWaitHandle.WaitAny(
|
||||
waitHandles,
|
||||
millisecondsTimeout,
|
||||
true);
|
||||
|
@ -242,7 +282,7 @@ namespace Amib.Threading.Internal
|
|||
/// Cleanup the work items queue, hence no more work
|
||||
/// items are allowed to be queue
|
||||
/// </summary>
|
||||
protected virtual void Cleanup()
|
||||
private void Cleanup()
|
||||
{
|
||||
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
|
||||
|
||||
#region Private methods
|
||||
|
@ -289,14 +344,14 @@ namespace Amib.Threading.Internal
|
|||
/// <returns></returns>
|
||||
/// In order to avoid creation and destuction of WaiterEntry
|
||||
/// 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();
|
||||
return _waiterEntry;
|
||||
CurrentWaiterEntry.Reset();
|
||||
return CurrentWaiterEntry;
|
||||
}
|
||||
|
||||
#region Waiters stack methods
|
||||
|
@ -418,14 +473,15 @@ namespace Amib.Threading.Internal
|
|||
#region WaiterEntry class
|
||||
|
||||
// A waiter entry in the _waiters queue.
|
||||
public class WaiterEntry : IDisposable
|
||||
public sealed class WaiterEntry : IDisposable
|
||||
{
|
||||
#region Member variables
|
||||
|
||||
/// <summary>
|
||||
/// Event to signal the waiter that it got the work item.
|
||||
/// </summary>
|
||||
private AutoResetEvent _waitHandle = new AutoResetEvent(false);
|
||||
//private AutoResetEvent _waitHandle = new AutoResetEvent(false);
|
||||
private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent();
|
||||
|
||||
/// <summary>
|
||||
/// Flag to know if this waiter already quited from the queue
|
||||
|
@ -471,13 +527,10 @@ namespace Amib.Threading.Internal
|
|||
public WorkItem WorkItem
|
||||
{
|
||||
get
|
||||
{
|
||||
lock(this)
|
||||
{
|
||||
return _workItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal the waiter that it got a work item.
|
||||
|
@ -550,18 +603,16 @@ namespace Amib.Threading.Internal
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
~WaiterEntry()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
@ -574,14 +625,8 @@ namespace Amib.Threading.Internal
|
|||
if (!_isDisposed)
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
_isDisposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
~WorkItemsQueue()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
private void ValidateNotDisposed()
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
|
||||
; *
|
||||
[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
|
||||
; Set path to directory for plugin registry. Information
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
; * [[<ConfigName>@]<port>/]<dll name>[:<class name>]
|
||||
; *
|
||||
[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
|
||||
; Set path to directory for plugin registry. Information
|
||||
|
@ -21,7 +24,6 @@
|
|||
; The Robust.exe process must have R/W access to the location
|
||||
RegistryLocation = "."
|
||||
|
||||
|
||||
; Modular configurations
|
||||
; Set path to directory for modular ini files...
|
||||
; The Robust.exe process must have R/W access to the location
|
||||
|
|
Loading…
Reference in New Issue