Added Work Item passive timeout

This commit is contained in:
Ami Bar
2009-12-19 20:49:16 +02:00
parent 5d037fdec8
commit ccfd49f237
6 changed files with 166 additions and 10 deletions
+3 -2
View File
@@ -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">
+2 -1
View File
@@ -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;
+126
View File
@@ -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();
}
}
}
+26 -5
View File
@@ -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;
} }
+1 -1
View File
@@ -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");
} }
+8 -1
View File
@@ -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