Skip to content

Commit

Permalink
Switch ParallelForEachUtility to use the Smart Thread Pool library (h…
Browse files Browse the repository at this point in the history
…ttps://github.com/amibar/SmartThreadPool).

Added a trimmed down copy to libs, some fixes to make it .net 3.5 client profile compatible.
  • Loading branch information
acgessler committed Apr 11, 2015
1 parent 09eb29b commit 9399da0
Show file tree
Hide file tree
Showing 31 changed files with 7,646 additions and 18 deletions.
24 changes: 24 additions & 0 deletions LICENSE_SmartThreadPool
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Source: https://github.com/amibar/SmartThreadPool
http://www.codeproject.com/Articles/7933/Smart-Thread-Pool

Microsoft Public License (MS-PL)

This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.

1. Definitions
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
same meaning here as under U.S. copyright law.
A "contribution" is the original software, or any additions or changes to the software.
A "contributor" is any person that distributes its contribution under this license.
"Licensed patents" are a contributor's patent claims that read directly on its contribution.

2. Grant of Rights
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.

3. Conditions and Limitations
(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
138 changes: 138 additions & 0 deletions libs/SmartThreadPool/SmartThreadPool/CallerThreadContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@

#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) && !(NO_SYSTEM_WEB)

using System;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using System.Web;
using System.Runtime.Remoting.Messaging;


namespace Amib.Threading.Internal
{
#region CallerThreadContext class

/// <summary>
/// This class stores the caller call context in order to restore
/// it when the work item is executed in the thread pool environment.
/// </summary>
internal class CallerThreadContext
{
#region Prepare reflection information

// Cached type information.
private static readonly MethodInfo getLogicalCallContextMethodInfo =
typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);

private static readonly MethodInfo setLogicalCallContextMethodInfo =
typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);

private static string HttpContextSlotName = GetHttpContextSlotName();

private static string GetHttpContextSlotName()
{
FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);

if (fi != null)
{
return (string) fi.GetValue(null);
}

return "HttpContext";
}

#endregion

#region Private fields

private HttpContext _httpContext;
private LogicalCallContext _callContext;

#endregion

/// <summary>
/// Constructor
/// </summary>
private CallerThreadContext()
{
}

public bool CapturedCallContext
{
get
{
return (null != _callContext);
}
}

public bool CapturedHttpContext
{
get
{
return (null != _httpContext);
}
}

/// <summary>
/// Captures the current thread context
/// </summary>
/// <returns></returns>
public static CallerThreadContext Capture(
bool captureCallContext,
bool captureHttpContext)
{
Debug.Assert(captureCallContext || captureHttpContext);

CallerThreadContext callerThreadContext = new CallerThreadContext();

// TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
// Capture Call Context
if(captureCallContext && (getLogicalCallContextMethodInfo != null))
{
callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
if (callerThreadContext._callContext != null)
{
callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
}
}

// Capture httpContext
if (captureHttpContext && (null != HttpContext.Current))
{
callerThreadContext._httpContext = HttpContext.Current;
}

return callerThreadContext;
}

/// <summary>
/// Applies the thread context stored earlier
/// </summary>
/// <param name="callerThreadContext"></param>
public static void Apply(CallerThreadContext callerThreadContext)
{
if (null == callerThreadContext)
{
throw new ArgumentNullException("callerThreadContext");
}

// Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
// Restore call context
if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
{
setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
}

// Restore HttpContext
if (callerThreadContext._httpContext != null)
{
HttpContext.Current = callerThreadContext._httpContext;
//CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
}
}
}

#endregion
}
#endif
14 changes: 14 additions & 0 deletions libs/SmartThreadPool/SmartThreadPool/CanceledWorkItemsGroup.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}
104 changes: 104 additions & 0 deletions libs/SmartThreadPool/SmartThreadPool/EventWaitHandle.cs
Original file line number Diff line number Diff line change
@@ -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
82 changes: 82 additions & 0 deletions libs/SmartThreadPool/SmartThreadPool/EventWaitHandleFactory.cs
Original file line number Diff line number Diff line change
@@ -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

}
}
Loading

0 comments on commit 9399da0

Please sign in to comment.