mirror of
https://github.com/farcasclaudiu/SmartThreadPool.git
synced 2026-06-22 09:01:19 +03:00
Added Work Item passive timeout
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ProjectType>Local</ProjectType>
|
<ProjectType>Local</ProjectType>
|
||||||
<ProductVersion>9.0.21022</ProductVersion>
|
<ProductVersion>9.0.30729</ProductVersion>
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
<ProjectGuid>{6A3E4DBF-12AD-4636-ACB3-24B5172FAE03}</ProjectGuid>
|
<ProjectGuid>{6A3E4DBF-12AD-4636-ACB3-24B5172FAE03}</ProjectGuid>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="nunit.framework, Version=2.4.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
|
<Reference Include="nunit.framework, Version=2.5.2.9222, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
|
||||||
<Reference Include="System">
|
<Reference Include="System">
|
||||||
<Name>System</Name>
|
<Name>System</Name>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -189,6 +189,7 @@
|
|||||||
<Compile Include="TestWorkItemsQueue.cs">
|
<Compile Include="TestWorkItemsQueue.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="TestWorkItemTimeout.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ namespace SmartThreadPoolTests
|
|||||||
|
|
||||||
stp.Shutdown();
|
stp.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 1. Create STP in suspended mode
|
/// 1. Create STP in suspended mode
|
||||||
/// 2. Queue work item into the STP
|
/// 2. Queue work item into the STP
|
||||||
@@ -173,7 +174,7 @@ namespace SmartThreadPoolTests
|
|||||||
stpStartInfo.StartSuspended = true;
|
stpStartInfo.StartSuspended = true;
|
||||||
|
|
||||||
SmartThreadPool stp = new SmartThreadPool(stpStartInfo);
|
SmartThreadPool stp = new SmartThreadPool(stpStartInfo);
|
||||||
IWorkItemResult wir = stp.QueueWorkItem(state => { return null; });
|
IWorkItemResult wir = stp.QueueWorkItem(state => null);
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
using Amib.Threading;
|
||||||
|
|
||||||
|
namespace SmartThreadPoolTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
[Category("TestWorkItemTimeout")]
|
||||||
|
public class TestWorkItemTimeout
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 1. Create STP in suspended mode
|
||||||
|
/// 2. Queue work item into the STP
|
||||||
|
/// 3. Wait for the work item to expire
|
||||||
|
/// 4. Work item's GetResult should throw WorkItemCancelException
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
[ExpectedException(typeof(WorkItemCancelException))]
|
||||||
|
public void CancelInQueueWorkItem()
|
||||||
|
{
|
||||||
|
STPStartInfo stpStartInfo = new STPStartInfo();
|
||||||
|
stpStartInfo.StartSuspended = true;
|
||||||
|
|
||||||
|
bool hasRun = false;
|
||||||
|
|
||||||
|
SmartThreadPool stp = new SmartThreadPool(stpStartInfo);
|
||||||
|
IWorkItemResult wir = stp.QueueWorkItem(
|
||||||
|
new WorkItemInfo()
|
||||||
|
{
|
||||||
|
Timeout = 1000 },
|
||||||
|
arg =>
|
||||||
|
{
|
||||||
|
hasRun = true;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Assert.IsFalse(wir.IsCanceled);
|
||||||
|
|
||||||
|
Thread.Sleep(2000);
|
||||||
|
|
||||||
|
Assert.IsTrue(wir.IsCanceled);
|
||||||
|
|
||||||
|
stp.Start();
|
||||||
|
stp.WaitForIdle();
|
||||||
|
|
||||||
|
Assert.IsFalse(hasRun);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
wir.GetResult();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
stp.Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1. Create STP
|
||||||
|
/// 2. Queue work item that takes some time
|
||||||
|
/// 3. Wait for it to start
|
||||||
|
/// 4. The work item timeout expires
|
||||||
|
/// 5. Make sure, in the work item, that SmartThreadPool.IsWorkItemCanceled is true
|
||||||
|
/// 5. Wait for the STP to get idle
|
||||||
|
/// 6. Work item's GetResult should throw WorkItemCancelException
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TimeoutInProgressWorkItemWithSample()
|
||||||
|
{
|
||||||
|
bool timedout = false;
|
||||||
|
ManualResetEvent waitToStart = new ManualResetEvent(false);
|
||||||
|
ManualResetEvent waitToComplete = new ManualResetEvent(false);
|
||||||
|
|
||||||
|
SmartThreadPool stp = new SmartThreadPool();
|
||||||
|
IWorkItemResult wir = stp.QueueWorkItem(
|
||||||
|
new WorkItemInfo() { Timeout = 1000 },
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
waitToStart.Set();
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
timedout = SmartThreadPool.IsWorkItemCanceled;
|
||||||
|
waitToComplete.Set();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
waitToStart.WaitOne();
|
||||||
|
|
||||||
|
waitToComplete.WaitOne();
|
||||||
|
|
||||||
|
Assert.IsTrue(timedout);
|
||||||
|
|
||||||
|
stp.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1. Create STP
|
||||||
|
/// 2. Queue work item into the STP
|
||||||
|
/// 3. Wait for the STP to get idle
|
||||||
|
/// 4. Work item's GetResult should return value
|
||||||
|
/// 4. The work item expires
|
||||||
|
/// 5. Work item's GetResult should return value
|
||||||
|
/// </summary>
|
||||||
|
[Test]
|
||||||
|
public void TimeoutCompletedWorkItem()
|
||||||
|
{
|
||||||
|
SmartThreadPool stp = new SmartThreadPool();
|
||||||
|
IWorkItemResult wir =
|
||||||
|
stp.QueueWorkItem(
|
||||||
|
new WorkItemInfo() { Timeout = 1000 },
|
||||||
|
state => 1);
|
||||||
|
|
||||||
|
stp.WaitForIdle();
|
||||||
|
|
||||||
|
Assert.AreEqual(wir.GetResult(), 1);
|
||||||
|
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
|
||||||
|
Assert.AreEqual(wir.GetResult(), 1);
|
||||||
|
|
||||||
|
stp.Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,11 +61,11 @@ namespace Amib.Threading.Internal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private object _state;
|
private object _state;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Stores the caller's context
|
|
||||||
/// </summary>
|
|
||||||
#if !(WindowsCE) && !(SILVERLIGHT)
|
#if !(WindowsCE) && !(SILVERLIGHT)
|
||||||
private readonly CallerThreadContext _callerContext;
|
/// <summary>
|
||||||
|
/// Stores the caller's context
|
||||||
|
/// </summary>
|
||||||
|
private readonly CallerThreadContext _callerContext;
|
||||||
#endif
|
#endif
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Holds the result of the mehtod
|
/// Holds the result of the mehtod
|
||||||
@@ -136,6 +136,11 @@ namespace Amib.Threading.Internal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private Thread _executingThread;
|
private Thread _executingThread;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The absulote time when the work item will be timeout
|
||||||
|
/// </summary>
|
||||||
|
private long _expirationTime;
|
||||||
|
|
||||||
#region Performance Counter fields
|
#region Performance Counter fields
|
||||||
|
|
||||||
|
|
||||||
@@ -227,6 +232,10 @@ namespace Amib.Threading.Internal
|
|||||||
_workItemCompletedRefCount = 0;
|
_workItemCompletedRefCount = 0;
|
||||||
_waitingOnQueueStopwatch = new Stopwatch();
|
_waitingOnQueueStopwatch = new Stopwatch();
|
||||||
_processingStopwatch = new Stopwatch();
|
_processingStopwatch = new Stopwatch();
|
||||||
|
_expirationTime =
|
||||||
|
_workItemInfo.Timeout > 0 ?
|
||||||
|
DateTime.UtcNow.Ticks + _workItemInfo.Timeout * TimeSpan.TicksPerMillisecond :
|
||||||
|
long.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup)
|
internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup)
|
||||||
@@ -625,7 +634,19 @@ namespace Amib.Threading.Internal
|
|||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
if (WorkItemState.Completed == _workItemState || WorkItemState.InProgress == _workItemState)
|
if (WorkItemState.Completed == _workItemState)
|
||||||
|
{
|
||||||
|
return _workItemState;
|
||||||
|
}
|
||||||
|
|
||||||
|
long nowTicks = DateTime.UtcNow.Ticks;
|
||||||
|
|
||||||
|
if (WorkItemState.Canceled != _workItemState && nowTicks > _expirationTime)
|
||||||
|
{
|
||||||
|
_workItemState = WorkItemState.Canceled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WorkItemState.InProgress == _workItemState)
|
||||||
{
|
{
|
||||||
return _workItemState;
|
return _workItemState;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ namespace Amib.Threading.Internal
|
|||||||
|
|
||||||
private static void ValidateCallback(Delegate callback)
|
private static void ValidateCallback(Delegate callback)
|
||||||
{
|
{
|
||||||
if(callback.GetInvocationList().Length > 1)
|
if (callback != null && callback.GetInvocationList().Length > 1)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
|
throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ namespace Amib.Threading
|
|||||||
CallToPostExecute = workItemInfo.CallToPostExecute;
|
CallToPostExecute = workItemInfo.CallToPostExecute;
|
||||||
PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback;
|
PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback;
|
||||||
WorkItemPriority = workItemInfo.WorkItemPriority;
|
WorkItemPriority = workItemInfo.WorkItemPriority;
|
||||||
|
Timeout = workItemInfo.Timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -53,9 +54,15 @@ namespace Amib.Threading
|
|||||||
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; }
|
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get/Set the work items priority
|
/// Get/Set the work item's priority
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public WorkItemPriority WorkItemPriority { get; set; }
|
public WorkItemPriority WorkItemPriority { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get/Set the work item's timout in milliseconds.
|
||||||
|
/// This is a passive timout. When the timout expires the work item won't be actively aborted!
|
||||||
|
/// </summary>
|
||||||
|
public long Timeout { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
Reference in New Issue
Block a user