-> IPScanner added
-> PortScanner added
This commit is contained in:
369
Networking/SmartThreadPool/WorkItemsGroup.cs
Normal file
369
Networking/SmartThreadPool/WorkItemsGroup.cs
Normal file
@@ -0,0 +1,369 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Amib.Threading.Internal
|
||||
{
|
||||
|
||||
#region WorkItemsGroup class
|
||||
|
||||
/// <summary>
|
||||
/// Summary description for WorkItemsGroup.
|
||||
/// </summary>
|
||||
public class WorkItemsGroup : WorkItemsGroupBase
|
||||
{
|
||||
#region Private members
|
||||
|
||||
private readonly object _lock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the SmartThreadPool instance that created this
|
||||
/// WorkItemsGroup.
|
||||
/// </summary>
|
||||
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>
|
||||
private int _concurrency;
|
||||
|
||||
/// <summary>
|
||||
/// Priority queue to hold work items before they are passed
|
||||
/// to the SmartThreadPool.
|
||||
/// </summary>
|
||||
private readonly PriorityQueue _workItemsQueue;
|
||||
|
||||
/// <summary>
|
||||
/// Indicate how many work items are waiting in the SmartThreadPool
|
||||
/// queue.
|
||||
/// This value is used to apply the concurrency.
|
||||
/// </summary>
|
||||
private int _workItemsInStpQueue;
|
||||
|
||||
/// <summary>
|
||||
/// Indicate how many work items are currently running in the SmartThreadPool.
|
||||
/// This value is used with the Cancel, to calculate if we can send new
|
||||
/// work items to the STP.
|
||||
/// </summary>
|
||||
private int _workItemsExecutingInStp = 0;
|
||||
|
||||
/// <summary>
|
||||
/// WorkItemsGroup start information
|
||||
/// </summary>
|
||||
private readonly WIGStartInfo _workItemsGroupStartInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Signaled when all of the WorkItemsGroup's work item completed.
|
||||
/// </summary>
|
||||
//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
|
||||
/// generate so we can mark them to cancel in O(1)
|
||||
/// </summary>
|
||||
private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction
|
||||
|
||||
public WorkItemsGroup(
|
||||
SmartThreadPool stp,
|
||||
int concurrency,
|
||||
WIGStartInfo wigStartInfo)
|
||||
{
|
||||
if (concurrency <= 0)
|
||||
{
|
||||
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).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 WorkItemsGroupBase Overrides
|
||||
|
||||
public override int Concurrency
|
||||
{
|
||||
get { return _concurrency; }
|
||||
set
|
||||
{
|
||||
Debug.Assert(value > 0);
|
||||
|
||||
int diff = value - _concurrency;
|
||||
_concurrency = value;
|
||||
if (diff > 0)
|
||||
{
|
||||
EnqueueToSTPNextNWorkItem(diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int InUseThreads
|
||||
{
|
||||
get
|
||||
{
|
||||
return _workItemsExecutingInStp;
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
/// WorkItemsGroup start information
|
||||
/// </summary>
|
||||
public override WIGStartInfo WIGStartInfo
|
||||
{
|
||||
get { return _workItemsGroupStartInfo; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the Work Items Group if it was started suspended
|
||||
/// </summary>
|
||||
public override void Start()
|
||||
{
|
||||
// If the Work Items Group already started then quit
|
||||
if (!_isSuspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_isSuspended = false;
|
||||
|
||||
EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency));
|
||||
}
|
||||
|
||||
public override void Cancel(bool abortExecution)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_canceledWorkItemsGroup.IsCanceled = true;
|
||||
_workItemsQueue.Clear();
|
||||
_workItemsInStpQueue = 0;
|
||||
_canceledWorkItemsGroup = new CanceledWorkItemsGroup();
|
||||
}
|
||||
|
||||
if (abortExecution)
|
||||
{
|
||||
_stp.CancelAbortWorkItemsGroup(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wait for the thread pool to be idle
|
||||
/// </summary>
|
||||
public override bool WaitForIdle(int millisecondsTimeout)
|
||||
{
|
||||
SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
|
||||
return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false);
|
||||
}
|
||||
|
||||
public override event WorkItemsGroupIdleHandler OnIdle
|
||||
{
|
||||
add { _onIdle += value; }
|
||||
remove { _onIdle -= value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
|
||||
private void RegisterToWorkItemCompletion(IWorkItemResult wir)
|
||||
{
|
||||
IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir;
|
||||
iwir.OnWorkItemStarted += OnWorkItemStartedCallback;
|
||||
iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback;
|
||||
}
|
||||
|
||||
public void OnSTPIsStarting()
|
||||
{
|
||||
if (_isSuspended)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnqueueToSTPNextNWorkItem(_concurrency);
|
||||
}
|
||||
|
||||
public void EnqueueToSTPNextNWorkItem(int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(null, false);
|
||||
}
|
||||
}
|
||||
|
||||
private object FireOnIdle(object state)
|
||||
{
|
||||
FireOnIdleImpl(_onIdle);
|
||||
return null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
|
||||
{
|
||||
if(null == onIdle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Delegate[] delegates = onIdle.GetInvocationList();
|
||||
foreach(WorkItemsGroupIdleHandler eh in delegates)
|
||||
{
|
||||
try
|
||||
{
|
||||
eh(this);
|
||||
}
|
||||
catch { } // Suppress exceptions
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWorkItemStartedCallback(WorkItem workItem)
|
||||
{
|
||||
lock(_lock)
|
||||
{
|
||||
++_workItemsExecutingInStp;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWorkItemCompletedCallback(WorkItem workItem)
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(null, true);
|
||||
}
|
||||
|
||||
internal override void Enqueue(WorkItem workItem)
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(workItem);
|
||||
}
|
||||
|
||||
private void EnqueueToSTPNextWorkItem(WorkItem workItem)
|
||||
{
|
||||
EnqueueToSTPNextWorkItem(workItem, false);
|
||||
}
|
||||
|
||||
private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue)
|
||||
{
|
||||
lock(_lock)
|
||||
{
|
||||
// Got here from OnWorkItemCompletedCallback()
|
||||
if (decrementWorkItemsInStpQueue)
|
||||
{
|
||||
--_workItemsInStpQueue;
|
||||
|
||||
if(_workItemsInStpQueue < 0)
|
||||
{
|
||||
_workItemsInStpQueue = 0;
|
||||
}
|
||||
|
||||
--_workItemsExecutingInStp;
|
||||
|
||||
if(_workItemsExecutingInStp < 0)
|
||||
{
|
||||
_workItemsExecutingInStp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If the work item is not null then enqueue it
|
||||
if (null != workItem)
|
||||
{
|
||||
workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup;
|
||||
|
||||
RegisterToWorkItemCompletion(workItem.GetWorkItemResult());
|
||||
_workItemsQueue.Enqueue(workItem);
|
||||
//_stp.IncrementWorkItemsCount();
|
||||
|
||||
if ((1 == _workItemsQueue.Count) &&
|
||||
(0 == _workItemsInStpQueue))
|
||||
{
|
||||
_stp.RegisterWorkItemsGroup(this);
|
||||
IsIdle = false;
|
||||
_isIdleWaitHandle.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// If the work items queue of the group is empty than quit
|
||||
if (0 == _workItemsQueue.Count)
|
||||
{
|
||||
if (0 == _workItemsInStpQueue)
|
||||
{
|
||||
_stp.UnregisterWorkItemsGroup(this);
|
||||
IsIdle = true;
|
||||
_isIdleWaitHandle.Set();
|
||||
if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0)
|
||||
{
|
||||
_stp.QueueWorkItem(new WorkItemCallback(FireOnIdle));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_isSuspended)
|
||||
{
|
||||
if (_workItemsInStpQueue < _concurrency)
|
||||
{
|
||||
WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
|
||||
try
|
||||
{
|
||||
_stp.Enqueue(nextWorkItem);
|
||||
}
|
||||
catch (ObjectDisposedException e)
|
||||
{
|
||||
e.GetHashCode();
|
||||
// The STP has been shutdown
|
||||
}
|
||||
|
||||
++_workItemsInStpQueue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user