SmartThreadPool v1.0
This commit is contained in:
Ami Bar
2009-12-19 16:27:08 +02:00
parent 8d9c132b24
commit b30b4abdda
65 changed files with 11818 additions and 27 deletions
+27 -27
View File
@@ -1,28 +1,28 @@
#ignore thumbnails created by windows
Thumbs.db
#Ignore files build by Visual Studio
*.obj
*.exe
*.pdb
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.log
[Bb]in
[Dd]ebug*/
*.lib
*.sbr
obj/
[Rr]elease*/
_ReSharper*/
#ignore thumbnails created by windows
Thumbs.db
#Ignore files build by Visual Studio
*.obj
*.exe
*.pdb
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.log
[Bb]in
[Dd]ebug*/
*.lib
*.sbr
obj/
[Rr]elease*/
_ReSharper*/
[Tt]est[Rr]esult*
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+58
View File
@@ -0,0 +1,58 @@
using System.Reflection;
using System.Runtime.CompilerServices;
//
// 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("")]
//
// 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("1.0.*")]
//
// 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("")]
+47
View File
@@ -0,0 +1,47 @@
using System;
using System.Diagnostics;
using Amib.Threading;
namespace Examples
{
public class CatchExceptionExample
{
private class DivArgs
{
public int x;
public int y;
}
public void DoWork()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
DivArgs divArgs = new DivArgs();
divArgs.x = 10;
divArgs.y = 0;
IWorkItemResult wir =
smartThreadPool.QueueWorkItem(new
WorkItemCallback(this.DoDiv), divArgs);
try
{
int result = (int)wir.Result;
}
// Catch the exception that Result threw
catch (WorkItemResultException e)
{
// Dump the inner exception which DoDiv threw
Debug.WriteLine(e.InnerException);
}
smartThreadPool.Shutdown();
}
private object DoDiv(object state)
{
DivArgs divArgs = (DivArgs)state;
return (divArgs.x / divArgs.y);
}
}
}
+47
View File
@@ -0,0 +1,47 @@
using System;
using Amib.Threading;
namespace Examples
{
public class GetExceptionExample
{
private class DivArgs
{
public int x;
public int y;
}
public void DoWork()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
DivArgs divArgs = new DivArgs();
divArgs.x = 10;
divArgs.y = 0;
IWorkItemResult wir =
smartThreadPool.QueueWorkItem(new
WorkItemCallback(this.DoDiv), divArgs);
Exception e = null;
object obj = wir.GetResult(out e);
// e contains the expetion that DoDiv threw
if(null == e)
{
int result = (int)obj;
}
else
{
// Do something with the exception
}
smartThreadPool.Shutdown();
}
private object DoDiv(object state)
{
DivArgs divArgs = (DivArgs)state;
return (divArgs.x / divArgs.y);
}
}
}
+38
View File
@@ -0,0 +1,38 @@
using System.Diagnostics;
using Amib.Threading;
namespace Examples
{
public class OnWIGIdleEventExample
{
public void DoWork(object [] states)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup wig = smartThreadPool.CreateWorkItemsGroup(1);
wig.OnIdle += new WorkItemsGroupIdleHandler(wig_OnIdle);
foreach(object state in states)
{
wig.QueueWorkItem(new
WorkItemCallback(this.DoSomeWork), state);
}
smartThreadPool.WaitForIdle();
smartThreadPool.Shutdown();
}
private object DoSomeWork(object state)
{
// Do the work
return null;
}
private void wig_OnIdle(IWorkItemsGroup workItemsGroup)
{
Debug.WriteLine("WIG is idle");
}
}
}
+39
View File
@@ -0,0 +1,39 @@
using System.Diagnostics;
using Amib.Threading;
namespace Examples
{
public class PriorityExample
{
public void DoWork()
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.StartSuspended = true;
SmartThreadPool smartThreadPool = new SmartThreadPool();
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
"Queued first",
WorkItemPriority.BelowNormal);
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
"Queued second",
WorkItemPriority.AboveNormal);
smartThreadPool.Start();
smartThreadPool.WaitForIdle();
smartThreadPool.Shutdown();
}
private object DoSomeWork(object state)
{
Debug.WriteLine(state);
return null;
}
}
}
+137
View File
@@ -0,0 +1,137 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectType>Local</ProjectType>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{AE943A5A-7CFD-4E0D-BA51-FB763AAEA9A3}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ApplicationIcon>App.ico</ApplicationIcon>
<AssemblyKeyContainerName>
</AssemblyKeyContainerName>
<AssemblyName>STPExamples</AssemblyName>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
<DefaultClientScript>JScript</DefaultClientScript>
<DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
<DefaultTargetSchema>IE50</DefaultTargetSchema>
<DelaySign>false</DelaySign>
<OutputType>Library</OutputType>
<RootNamespace>STPExamples</RootNamespace>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<StartupObject>
</StartupObject>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>false</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>bin\Release\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>false</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>true</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>none</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System">
<Name>System</Name>
</Reference>
<Reference Include="System.Data">
<Name>System.Data</Name>
</Reference>
<Reference Include="System.Xml">
<Name>System.XML</Name>
</Reference>
<ProjectReference Include="..\SmartThreadPool\SmartThreadPool.csproj">
<Name>SmartThreadPool</Name>
<Project>{8684FC56-A679-4E2E-8F96-E172FB062EB6}</Project>
<Package>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Package>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="App.ico" />
<Compile Include="AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="CatchExceptionExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="GetExceptionExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="OnWIGIdleEventExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="PriorityExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SimpleExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SuspendedSTPStartExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SuspendedWIGStartExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WaitForAllExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WaitForAnyExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WaitForIdleExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WorkItemsGroupExample.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
+35
View File
@@ -0,0 +1,35 @@
using Amib.Threading;
namespace Examples
{
public class SimpleExample
{
public void DoWork(object state)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
// Queue the work item
IWorkItemResult wir =
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoRealWork),
state);
// Do some other work here
// Get the result of the operation
object result = wir.Result;
smartThreadPool.Shutdown();
}
// Do the real work
private object DoRealWork(object state)
{
object result = null;
// Do the real work here and put the result in 'result'
return result;
}
}
}
+36
View File
@@ -0,0 +1,36 @@
using System;
using Amib.Threading;
namespace Examples
{
public class SuspendedSTPStartExample
{
public void DoWork(object [] states)
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.StartSuspended = true;
SmartThreadPool smartThreadPool = new SmartThreadPool(stpStartInfo);
foreach(object state in states)
{
smartThreadPool.QueueWorkItem(new
WorkItemCallback(this.DoSomeWork), state);
}
// Start working on the work items in the queue
smartThreadPool.Start();
// Wait for the completion of all work items
smartThreadPool.WaitForIdle();
smartThreadPool.Shutdown();
}
private object DoSomeWork(object state)
{
// Do the work
return null;
}
}
}
+39
View File
@@ -0,0 +1,39 @@
using System;
using Amib.Threading;
namespace Examples
{
public class SuspendedWIGStartExample
{
public void DoWork(object [] states)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
WIGStartInfo wigStartInfo = new WIGStartInfo();
wigStartInfo.StartSuspended = true;
IWorkItemsGroup wig = smartThreadPool.CreateWorkItemsGroup(1, wigStartInfo);
foreach(object state in states)
{
wig.QueueWorkItem(new
WorkItemCallback(this.DoSomeWork), state);
}
// Start working on the work items in the work items group queue
wig.Start();
// Wait for the completion of all work items
wig.WaitForIdle();
smartThreadPool.Shutdown();
}
private object DoSomeWork(object state)
{
// Do the work
return null;
}
}
}
+40
View File
@@ -0,0 +1,40 @@
using Amib.Threading;
namespace Examples
{
public class WaitForAllExample
{
public void DoWork()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemResult wir1 =
smartThreadPool.QueueWorkItem(new
WorkItemCallback(this.DoSomeWork1), null);
IWorkItemResult wir2 =
smartThreadPool.QueueWorkItem(new
WorkItemCallback(this.DoSomeWork2), null);
bool success = SmartThreadPool.WaitAll(new IWorkItemResult [] { wir1, wir2 });
if (success)
{
int result1 = (int)wir1.Result;
int result2 = (int)wir2.Result;
}
smartThreadPool.Shutdown();
}
private object DoSomeWork1(object state)
{
return 1;
}
private object DoSomeWork2(object state)
{
return 2;
}
}
}
+43
View File
@@ -0,0 +1,43 @@
using System.Threading;
using Amib.Threading;
namespace Examples
{
public class WaitForAnyExample
{
public void DoWork()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemResult wir1 =
smartThreadPool.QueueWorkItem(new
WorkItemCallback(this.DoSomeWork1), null);
IWorkItemResult wir2 =
smartThreadPool.QueueWorkItem(new
WorkItemCallback(this.DoSomeWork2), null);
IWorkItemResult [] wirs = new IWorkItemResult [] { wir1, wir2 };
int index = SmartThreadPool.WaitAny(wirs);
if (index != WaitHandle.WaitTimeout)
{
int result = (int)wirs[index].Result;
}
smartThreadPool.Shutdown();
}
private object DoSomeWork1(object state)
{
return 1;
}
private object DoSomeWork2(object state)
{
return 1;
}
}
}
+29
View File
@@ -0,0 +1,29 @@
using Amib.Threading;
namespace Examples
{
public class WaitForIdleExample
{
public void DoWork(object [] states)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
foreach(object state in states)
{
smartThreadPool.QueueWorkItem(new
WorkItemCallback(this.DoSomeWork), state);
}
// Wait for the completion of all work items
smartThreadPool.WaitForIdle();
smartThreadPool.Shutdown();
}
private object DoSomeWork(object state)
{
// Do the work
return null;
}
}
}
+34
View File
@@ -0,0 +1,34 @@
using System;
using Amib.Threading;
namespace Examples
{
public class WorkItemsGroupExample
{
public void DoWork(object [] states)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
// Create a work items group that processes
// one work item at a time
IWorkItemsGroup wig = smartThreadPool.CreateWorkItemsGroup(1);
// Queue some work items
foreach(object state in states)
{
wig.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), state);
}
// Wait for the completion of all work items in the work items group
wig.WaitForIdle();
smartThreadPool.Shutdown();
}
private object DoSomeWork(object state)
{
// Do the work
return null;
}
}
}
+58
View File
@@ -0,0 +1,58 @@
using System.Reflection;
using System.Runtime.CompilerServices;
//
// 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("")]
//
// 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("1.0.*")]
//
// 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("")]
+225
View File
@@ -0,0 +1,225 @@
using System;
using System.Collections;
using NUnit.Framework;
using Amib.Threading;
/*
* The code below generates permutations.
*
* The original code was written by Michael Gilleland,
* and can be found in the following site
* http://www.merriampark.com/perm.htm
*
* I translated it to C# from Java.
*/
namespace SmartThreadPoolTests
{
//--------------------------------------
// Systematically generate permutations.
//--------------------------------------
public class PermutationGenerator : IEnumerable
{
private object [] _objects;
public PermutationGenerator(object [] objects)
{
_objects = (object [])objects.Clone();
}
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
return new PermutationGeneratorEnumerator(_objects);
}
#endregion
private class PermutationGeneratorEnumerator : IEnumerator
{
private object [] _objects;
private object [] _currentPermutation;
private PermutationGeneratorHelper _permutationGeneratorHelper;
public PermutationGeneratorEnumerator(object [] objects)
{
_objects = objects;
Reset();
}
#region IEnumerator Members
public void Reset()
{
_permutationGeneratorHelper = new PermutationGeneratorHelper(_objects.Length);
}
public object Current
{
get
{
return _currentPermutation;
}
}
public bool MoveNext()
{
if (_permutationGeneratorHelper.hasMore())
{
_currentPermutation = new object[_objects.Length];
int [] indices = _permutationGeneratorHelper.getNext();
for (int i = 0; i < indices.Length; i++)
{
_currentPermutation[i] = _objects[indices[i]];
}
return true;
}
_currentPermutation = null;
return false;
}
#endregion
}
private class PermutationGeneratorHelper
{
private int[] a;
private long numLeft;
private long total;
//-----------------------------------------------------------
// Constructor. WARNING: Don't make n too large.
// Recall that the number of permutations is n!
// which can be very large, even when n is as small as 20 --
// 20! = 2,432,902,008,176,640,000 and
// 21! is too big to fit into a Java long, which is
// why we use long instead.
//----------------------------------------------------------
public PermutationGeneratorHelper (int n)
{
if (n < 1)
{
throw new ArgumentOutOfRangeException("n", n, "Min 1");
}
a = new int[n];
total = getFactorial (n);
reset();
}
//------
// Reset
//------
public void reset ()
{
for (int i = 0; i < a.Length; i++)
{
a[i] = i;
}
numLeft = total;
}
//------------------------------------------------
// Return number of permutations not yet generated
//------------------------------------------------
public long getNumLeft ()
{
return numLeft;
}
//------------------------------------
// Return total number of permutations
//------------------------------------
public long getTotal ()
{
return total;
}
//-----------------------------
// Are there more permutations?
//-----------------------------
public bool hasMore ()
{
return (numLeft > 0);
}
//------------------
// Compute factorial
//------------------
private static long getFactorial (int n)
{
long fact = 1;
for (int i = n; i > 1; i--)
{
fact = fact * i;
}
return fact;
}
//--------------------------------------------------------
// Generate next permutation (algorithm from Rosen p. 284)
//--------------------------------------------------------
public int[] getNext ()
{
if (numLeft == total)
{
--numLeft;
return a;
}
int temp;
// Find largest index j with a[j] < a[j+1]
int j = a.Length - 2;
while (a[j] > a[j+1])
{
j--;
}
// Find index k such that a[k] is smallest integer
// greater than a[j] to the right of a[j]
int k = a.Length - 1;
while (a[j] > a[k])
{
k--;
}
// Interchange a[j] and a[k]
temp = a[k];
a[k] = a[j];
a[j] = temp;
// Put tail end of permutation after jth position in increasing order
int r = a.Length - 1;
int s = j + 1;
while (r > s)
{
temp = a[s];
a[s] = a[r];
a[r] = temp;
r--;
s++;
}
--numLeft;
return a;
}
}
}
}
+168
View File
@@ -0,0 +1,168 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectType>Local</ProjectType>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{6A3E4DBF-12AD-4636-ACB3-24B5172FAE03}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ApplicationIcon>
</ApplicationIcon>
<AssemblyKeyContainerName>
</AssemblyKeyContainerName>
<AssemblyName>STPTests</AssemblyName>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
<DefaultClientScript>JScript</DefaultClientScript>
<DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
<DefaultTargetSchema>IE50</DefaultTargetSchema>
<DelaySign>false</DelaySign>
<OutputType>Library</OutputType>
<RootNamespace>STPTests</RootNamespace>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<StartupObject>
</StartupObject>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>false</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>bin\Release\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>false</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>true</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>none</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework, Version=2.2.5.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
<Reference Include="System">
<Name>System</Name>
</Reference>
<Reference Include="System.Data">
<Name>System.Data</Name>
</Reference>
<Reference Include="System.Xml">
<Name>System.XML</Name>
</Reference>
<ProjectReference Include="..\SmartThreadPool\SmartThreadPool.csproj">
<Name>SmartThreadPool</Name>
<Project>{8684FC56-A679-4E2E-8F96-E172FB062EB6}</Project>
<Package>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Package>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="PermutationGenerator.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestChainedDelegates.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestExceptions.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestGetResult.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestMultipleWorkItems.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestPostExecute.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestPriorityQueue.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestStartSuspended.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestStateDispose.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestThreadPriority.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWaitForIdle.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWIGChainedDelegates.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWIGConcurrency.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWIGExceptions.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWIGGetResult.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWIGMultipleWorkItems.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWIGPostExecute.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWIGStateDispose.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWIGWaitForIdle.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWorkItemsGroups.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestWorkItemsQueue.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
+97
View File
@@ -0,0 +1,97 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for TestChainedDelegates.
/// </summary>
[TestFixture]
[Category("TestChainedDelegates")]
public class TestChainedDelegates
{
public TestChainedDelegates()
{
}
[Test]
public void GoodCallback()
{
SmartThreadPool stp = new SmartThreadPool();
stp.QueueWorkItem(new WorkItemCallback(DoWork));
stp.WaitForIdle();
stp.Shutdown();
}
[Test]
[ExpectedException(typeof(NotSupportedException))]
public void ChainedDelegatesCallback()
{
SmartThreadPool stp = new SmartThreadPool();
WorkItemCallback workItemCallback = new WorkItemCallback(DoWork);
workItemCallback += new WorkItemCallback(DoWork);
stp.QueueWorkItem(workItemCallback);
stp.WaitForIdle();
stp.Shutdown();
}
[Test]
public void GoodPostExecute()
{
SmartThreadPool stp = new SmartThreadPool();
stp.QueueWorkItem(
new WorkItemCallback(DoWork),
null,
new PostExecuteWorkItemCallback(DoPostExecute));
stp.WaitForIdle();
stp.Shutdown();
}
[Test]
[ExpectedException(typeof(NotSupportedException))]
public void ChainedDelegatesPostExecute()
{
SmartThreadPool stp = new SmartThreadPool();
PostExecuteWorkItemCallback postExecuteWorkItemCallback =
new PostExecuteWorkItemCallback(DoPostExecute);
postExecuteWorkItemCallback +=
new PostExecuteWorkItemCallback(DoPostExecute);
stp.QueueWorkItem(
new WorkItemCallback(DoWork),
null,
postExecuteWorkItemCallback);
stp.WaitForIdle();
stp.Shutdown();
}
private object DoWork(object state)
{
return null;
}
private void DoPostExecute(IWorkItemResult wir)
{
}
}
}
+87
View File
@@ -0,0 +1,87 @@
using System;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for TestExceptions.
/// </summary>
[TestFixture]
[Category("TestExceptions")]
public class TestExceptions
{
private class DivArgs
{
public int x;
public int y;
}
[Test]
public void ExceptionThrowing()
{
SmartThreadPool _smartThreadPool = new SmartThreadPool();
DivArgs divArgs = new DivArgs();
divArgs.x = 10;
divArgs.y = 0;
IWorkItemResult wir =
_smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoDiv), divArgs);
try
{
wir.GetResult();
}
catch(WorkItemResultException wire)
{
Assert.IsTrue(wire.InnerException is DivideByZeroException);
return;
}
catch(Exception e)
{
e.GetHashCode();
Assert.Fail();
}
Assert.Fail();
}
[Test]
public void ExceptionReturning()
{
bool success = true;
SmartThreadPool _smartThreadPool = new SmartThreadPool();
DivArgs divArgs = new DivArgs();
divArgs.x = 10;
divArgs.y = 0;
IWorkItemResult wir =
_smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoDiv), divArgs);
Exception e = null;
try
{
wir.GetResult(out e);
}
catch (Exception ex)
{
ex.GetHashCode();
success = false;
}
Assert.IsTrue(success);
Assert.IsTrue(e is DivideByZeroException);
}
private object DoDiv(object state)
{
DivArgs divArgs = (DivArgs)state;
return (divArgs.x / divArgs.y);
}
}
}
+198
View File
@@ -0,0 +1,198 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for GetResultExample.
/// </summary>
[TestFixture]
[Category("TestGetResult")]
public class TestGetResult
{
/// <summary>
/// Example of how to queue a work item and then wait infinitely for the result.
/// </summary>
[Test]
public void BlockingCall()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = false;
IWorkItemResult wir =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
if (!wir.IsCompleted)
{
int result = (int)wir.GetResult();
success = (1 == result);
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue a work item and then wait on a timeout for the result.
/// </summary>
[Test]
public void Timeout()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = false;
IWorkItemResult wir =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
try
{
wir.GetResult(500, true);
}
catch (WorkItemTimeoutException)
{
success = true;
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue a work item and then cancel it while it is in the queue.
/// </summary>
[Test]
public void WorkItemCanceling()
{
// Create a SmartThreadPool with only one thread.
// It just to show how to use the work item canceling feature
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 1);
bool success = false;
// Queue a work item that will occupy the thread in the pool
IWorkItemResult wir1 =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
// Queue another work item that will wait for the first to complete
IWorkItemResult wir2 =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
// Wait a while for the thread pool to start executing the first work item
Thread.Sleep(100);
// The first work item cannot be canceled since it is currently executing
if (!wir1.Cancel())
{
// Cancel the second work item while it still in the queue
if (wir2.Cancel())
{
try
{
// Retreiving result of a canceled work item throws an exception
wir2.GetResult();
}
catch (WorkItemCancelException)
{
success = true;
}
}
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to interrupt the waiting for a work item to complete.
/// </summary>
[Test]
public void WorkItemWaitCanceling()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
ManualResetEvent cancelWaitHandle = new ManualResetEvent(false);
bool success = false;
// Queue a work item that will occupy the thread in the pool
IWorkItemResult wir1 =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
// Queue another work item that will wait for the first to complete
IWorkItemResult wir2 =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.SignalCancel), cancelWaitHandle);
try
{
wir1.GetResult(System.Threading.Timeout.Infinite, true, cancelWaitHandle);
}
catch (WorkItemTimeoutException)
{
success = true;
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue a work item and then cancel it while it is in the queue.
/// </summary>
[Test]
public void WorkItemCancelingAndInUseWorkerThreads()
{
// Create a SmartThreadPool with only one thread.
// It just to show how to use the work item canceling feature
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 10);
IWorkItemResult [] wirs = new IWorkItemResult[100];
for(int i = 0; i < 100; ++i)
{
wirs[i] = smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
// Wait a while for the thread pool to start executing the first work item
Thread.Sleep(100);
for(int i = 0; i < 100; ++i)
{
wirs[i].Cancel();
}
smartThreadPool.WaitForIdle(2000);
int inUseThreads = smartThreadPool.InUseThreads;
smartThreadPool.Shutdown();
Assert.AreEqual(0, inUseThreads);
}
private object DoSomeWork(object state)
{
Thread.Sleep(1000);
return 1;
}
private object SignalCancel(object state)
{
ManualResetEvent cancelWaitHandle = state as ManualResetEvent;
Thread.Sleep(250);
cancelWaitHandle.Set();
return null;
}
}
}
+232
View File
@@ -0,0 +1,232 @@
using System;
using System.Diagnostics;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for MultipleWorkItemsExample.
/// </summary>
[TestFixture]
[Category("TestMultipleWorkItems")]
public class TestMultipleWorkItems
{
/// <summary>
/// Example of how to queue several work items and then wait infinitely for
/// all of them to complete.
/// </summary>
[Test]
public void WaitAll()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = true;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
SmartThreadPool.WaitAll(wirs);
for(int i = 0; i < wirs.Length; ++i)
{
if (!wirs[i].IsCompleted)
{
success = false;
break;
}
else
{
int result = (int)wirs[i].GetResult();
if (1 != result)
{
success = false;
break;
}
}
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue several work items and then wait infinitely for
/// one of them to complete.
///
/// You can use this technique if you have several work items that return the same
/// infomration, but use different method to aquire it. Just execute all of them at
/// once and wait for the first work item to complete.
///
/// For example: You need an information about a person and you can query several
/// information sites (FBI, CIA, etc.). Query all of them at once and use the first
/// answer to arrive.
/// </summary>
[Test]
public void WaitAny()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = false;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
int index = SmartThreadPool.WaitAny(wirs);
if (wirs[index].IsCompleted)
{
int result = (int)wirs[index].GetResult();
if (1 == result)
{
success = true;
}
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue several work items and then wait on a timeout for all
/// of them to complete.
/// </summary>
[Test]
public void WaitAllWithTimeoutSuccess()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = true;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
bool timeout = !SmartThreadPool.WaitAll(wirs, 1500, true);
success = !timeout;
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue several work items and then wait on a timeout for all
/// of them to complete.
/// </summary>
[Test]
public void WaitAllWithTimeoutFailure()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = true;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
bool timeout = !SmartThreadPool.WaitAll(wirs, 10, true);
success = timeout;
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue several work items and then wait on a timeout for any
/// of them to complete.
/// </summary>
[Test]
public void WaitAnyWithTimeoutSuccess()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = true;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
int index = SmartThreadPool.WaitAny(wirs, 1500, true);
success = (index != WaitHandle.WaitTimeout);
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue several work items and then wait on a timeout for any
/// of them to complete.
/// </summary>
[Test]
public void WaitAnyWithTimeoutFailure()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = true;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
int index = SmartThreadPool.WaitAny(wirs, 10, true);
success = (index == WaitHandle.WaitTimeout);
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
[Test]
public void WaitAllWithEmptyArray()
{
IWorkItemResult [] wirs = new IWorkItemResult[0];
bool success = SmartThreadPool.WaitAll(wirs);;
Assert.IsTrue(success);
}
private object DoSomeWork(object state)
{
Thread.Sleep(1000);
return 1;
}
}
}
+227
View File
@@ -0,0 +1,227 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for DoTestPostExecute.
/// </summary>
[TestFixture]
[Category("DoTestPostExecute")]
public class TestPostExecution
{
/// <summary>
///
/// </summary>
[Test]
public void DefaultPostExecute_AlwaysCall()
{
Assert.IsTrue(DoTestDefaultPostExecute(CallToPostExecute.Always, true));
}
[Test]
public void DefaultPostExecute_NeverCall()
{
Assert.IsTrue(DoTestDefaultPostExecute(CallToPostExecute.Never, false));
}
[Test]
public void DefaultPostExecute_CallWhenCanceled()
{
Assert.IsTrue(DoTestDefaultPostExecute(CallToPostExecute.WhenWorkItemCanceled, false));
}
[Test]
public void DefaultPostExecute_CallWhenNotCanceled()
{
Assert.IsTrue(DoTestDefaultPostExecute(CallToPostExecute.WhenWorkItemNotCanceled, true));
}
/// <summary>
///
/// </summary>
[Test]
public void PostExecute_AlwaysCall()
{
Assert.IsTrue(DoTestPostExecute(CallToPostExecute.Always, true));
}
[Test]
public void PostExecute_NeverCall()
{
Assert.IsTrue(DoTestPostExecute(CallToPostExecute.Never, false));
}
[Test]
public void PostExecute_CallWhenCanceled()
{
Assert.IsTrue(DoTestPostExecute(CallToPostExecute.WhenWorkItemCanceled, false));
}
[Test]
public void PostExecute_CallWhenNotCanceled()
{
Assert.IsTrue(DoTestPostExecute(CallToPostExecute.WhenWorkItemNotCanceled, true));
}
/// <summary>
///
/// </summary>
[Test]
public void PostExecuteWithCancel_AlwaysCall()
{
Assert.IsTrue(DoTestPostExecuteWithCancel(CallToPostExecute.Always, true));
}
[Test]
public void PostExecuteWithCancel_NeverCall()
{
Assert.IsTrue(DoTestPostExecuteWithCancel(CallToPostExecute.Never, false));
}
[Test]
public void PostExecuteWithCancel_CallWhenCanceled()
{
Assert.IsTrue(DoTestPostExecuteWithCancel(CallToPostExecute.WhenWorkItemCanceled, true));
}
[Test]
public void PostExecuteWithCancel_CallWhenNotCanceled()
{
Assert.IsTrue(DoTestPostExecuteWithCancel(CallToPostExecute.WhenWorkItemNotCanceled, false));
}
private class PostExecuteResult
{
public ManualResetEvent wh = new ManualResetEvent(false);
}
/// <summary>
/// Example of how to use the post execute callback
/// </summary>
private bool DoTestDefaultPostExecute(CallToPostExecute callToPostExecute, bool answer)
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.CallToPostExecute = callToPostExecute;
stpStartInfo.PostExecuteWorkItemCallback = new PostExecuteWorkItemCallback(this.DoSomePostExecuteWork);
SmartThreadPool smartThreadPool = new SmartThreadPool(stpStartInfo);
bool success = false;
PostExecuteResult postExecuteResult = new PostExecuteResult();
IWorkItemResult wir =
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
postExecuteResult);
if (!wir.IsCompleted)
{
int result = (int)wir.GetResult();
success = (1 == result);
success = success && (postExecuteResult.wh.WaitOne(1000, true) == answer);
}
smartThreadPool.Shutdown();
return success;
}
/// <summary>
/// Example of how to use the post execute callback
/// </summary>
private bool DoTestPostExecute(CallToPostExecute callToPostExecute, bool answer)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = false;
PostExecuteResult postExecuteResult = new PostExecuteResult();
IWorkItemResult wir =
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
postExecuteResult,
new PostExecuteWorkItemCallback(this.DoSomePostExecuteWork),
callToPostExecute);
if (!wir.IsCompleted)
{
int result = (int)wir.GetResult();
success = (1 == result);
success = success && (postExecuteResult.wh.WaitOne(1000, true) == answer);
}
smartThreadPool.Shutdown();
return success;
}
/// <summary>
/// Example of how to queue a work item and then cancel it while it is in the queue.
/// </summary>
private bool DoTestPostExecuteWithCancel(CallToPostExecute callToPostExecute, bool answer)
{
// Create a SmartThreadPool with only one thread.
// It just to show how to use the work item canceling feature
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 1);
bool success = false;
PostExecuteResult postExecuteResult = new PostExecuteResult();
// Queue a work item that will occupy the thread in the pool
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
// Queue another work item that will wait for the first to complete
IWorkItemResult wir =
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
postExecuteResult,
new PostExecuteWorkItemCallback(this.DoSomePostExecuteWork),
callToPostExecute);
// Wait a while for the thread pool to start executing the first work item
Thread.Sleep(100);
// Cancel the second work item while it still in the queue
if (wir.Cancel())
{
success = (postExecuteResult.wh.WaitOne(1000, true) == answer);
}
smartThreadPool.Shutdown();
return success;
}
private object DoSomeWork(object state)
{
Thread.Sleep(1000);
return 1;
}
private void DoSomePostExecuteWork(IWorkItemResult wir)
{
PostExecuteResult postExecuteResult = wir.State as PostExecuteResult;
postExecuteResult.wh.Set();
}
private object SignalCancel(object state)
{
ManualResetEvent cancelWaitHandle = state as ManualResetEvent;
Thread.Sleep(250);
cancelWaitHandle.Set();
return null;
}
}
}
+169
View File
@@ -0,0 +1,169 @@
using System;
using NUnit.Framework;
using Amib.Threading;
using Amib.Threading.Internal;
using SmartThreadPoolTests;
namespace PriorityQueueTests
{
/// <summary>
/// Summary description for TestPriorityQueue.
/// </summary>
[TestFixture]
[Category("TestPriorityQueue")]
public class TestPriorityQueue
{
public TestPriorityQueue()
{
}
[Test]
public void Init()
{
PriorityQueue pq = new PriorityQueue();
Assert.AreEqual(0, pq.Count);
Assert.IsNull(pq.Dequeue());
Assert.AreEqual(0, pq.Count);
}
[Test]
public void OneWorkItem()
{
WorkItemPriority [] priorities = Enum.GetValues(typeof(WorkItemPriority)) as WorkItemPriority [];
foreach(WorkItemPriority wip in priorities)
{
PriorityQueue pq = new PriorityQueue();
PriorityItem pi = new PriorityItem(wip);
pq.Enqueue(pi);
Assert.AreEqual(1, pq.Count, "Failed for priority {0}", wip);
PriorityItem pi2 = pq.Dequeue() as PriorityItem;
Assert.IsNotNull(pi2, "Failed for priority {0}", wip);
Assert.AreSame(pi, pi2, "Failed for priority {0}", wip);
Assert.AreEqual(0, pq.Count, "Failed for priority {0}", wip);
}
}
[Test]
public void MultipleWorkItemsOnePriority()
{
WorkItemPriority [] priorities = Enum.GetValues(typeof(WorkItemPriority)) as WorkItemPriority [];
foreach(WorkItemPriority wip in priorities)
{
PriorityQueue pq = new PriorityQueue();
PriorityItem [] priorityItems = new PriorityItem[10];
for(int i = 0; i < priorityItems.Length; ++i)
{
priorityItems[i] = new PriorityItem(wip);
pq.Enqueue(priorityItems[i]);
Assert.AreEqual(i+1, pq.Count, "Failed for priority {0} item count {1}", wip, i+1);
}
for(int i = 0; i < priorityItems.Length; ++i)
{
PriorityItem pi = pq.Dequeue() as PriorityItem;
Assert.AreEqual(priorityItems.Length-(i+1), pq.Count, "Failed for priority {0} item count {1}", wip, i+1);
Assert.IsNotNull(pi, "Failed for priority {0} item count {1}", wip, i+1);
Assert.AreSame(pi, priorityItems[i], "Failed for priority {0} item count {1}", wip, i+1);
}
Assert.AreEqual(0, pq.Count, "Failed for priority {0}", wip);
Assert.IsNull(pq.Dequeue());
Assert.AreEqual(0, pq.Count);
}
}
[Test]
public void MultipleWorkItemsMultiplePriorities()
{
// Get all the available priorities
WorkItemPriority [] priorities = Enum.GetValues(typeof(WorkItemPriority)) as WorkItemPriority [];
// Create an array of priority items
PriorityItem [] priorityItems = new PriorityItem[priorities.Length];
// Create a priority item for each priority
int i = priorities.Length;
foreach(WorkItemPriority workItemPriority in priorities)
{
--i;
priorityItems[i] = new PriorityItem(workItemPriority);
}
// Create a PermutationGenerator for the priority items
PermutationGenerator permutations = new PermutationGenerator(priorityItems);
int count = 0;
// Iterate over the permutations
foreach(object [] permutation in permutations)
{
++count;
Console.Write("Permutation #" + count + " : ");
for(int j = 0; j < permutation.Length; ++j)
{
PriorityItem pi = permutation[j] as PriorityItem;
Console.Write(pi.WorkItemPriority + ", ");
}
Console.WriteLine();
// Create a priority queue
PriorityQueue pq = new PriorityQueue();
// Enqueue each priority item according to the permutation
for(i = 0; i < permutation.Length; ++i)
{
PriorityItem priorityItem = permutation[i] as PriorityItem;
pq.Enqueue(priorityItem);
}
// Make sure all the priority items are in the queue
Assert.AreEqual(priorityItems.Length, pq.Count);
// Compare the order of the priority items
for(i = 0; i < priorityItems.Length; ++i)
{
PriorityItem priorityItem = pq.Dequeue() as PriorityItem;
Assert.AreSame(priorityItems[i], priorityItem);
}
}
}
private class PriorityItem : IHasWorkItemPriority
{
private WorkItemPriority _workItemPriority;
public PriorityItem(WorkItemPriority workItemPriority)
{
_workItemPriority = workItemPriority;
}
public WorkItemPriority WorkItemPriority
{
get
{
return _workItemPriority;
}
}
}
}
}
+121
View File
@@ -0,0 +1,121 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for TestStartSuspended.
/// </summary>
[TestFixture]
[Category("TestStartSuspended")]
public class TestStartSuspended
{
public TestStartSuspended()
{
}
[Test]
public void StartSuspended()
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.StartSuspended = true;
SmartThreadPool stp = new SmartThreadPool(stpStartInfo);
stp.QueueWorkItem(new WorkItemCallback(this.DoWork));
Assert.IsFalse(stp.WaitForIdle(200));
stp.Start();
Assert.IsTrue(stp.WaitForIdle(200));
}
[Test]
public void WIGStartSuspended()
{
SmartThreadPool stp = new SmartThreadPool();
WIGStartInfo wigStartInfo = new WIGStartInfo();
wigStartInfo.StartSuspended = true;
IWorkItemsGroup wig = stp.CreateWorkItemsGroup(10, wigStartInfo);
wig.QueueWorkItem(new WorkItemCallback(this.DoWork));
Assert.IsFalse(wig.WaitForIdle(200));
wig.Start();
Assert.IsTrue(wig.WaitForIdle(200));
}
[Test]
public void STPAndWIGStartSuspended()
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.StartSuspended = true;
SmartThreadPool stp = new SmartThreadPool(stpStartInfo);
WIGStartInfo wigStartInfo = new WIGStartInfo();
wigStartInfo.StartSuspended = true;
IWorkItemsGroup wig = stp.CreateWorkItemsGroup(10, wigStartInfo);
wig.QueueWorkItem(new WorkItemCallback(this.DoWork));
Assert.IsFalse(wig.WaitForIdle(200));
wig.Start();
Assert.IsFalse(wig.WaitForIdle(200));
stp.Start();
Assert.IsTrue(wig.WaitForIdle(200));
Assert.IsTrue(stp.WaitForIdle(0));
}
[Test]
public void TwoWIGsStartSuspended()
{
SmartThreadPool stp = new SmartThreadPool();
WIGStartInfo wigStartInfo = new WIGStartInfo();
wigStartInfo.StartSuspended = true;
IWorkItemsGroup wig1 = stp.CreateWorkItemsGroup(10, wigStartInfo);
IWorkItemsGroup wig2 = stp.CreateWorkItemsGroup(10, wigStartInfo);
wig1.QueueWorkItem(new WorkItemCallback(this.DoWork));
wig2.QueueWorkItem(new WorkItemCallback(this.DoWork));
Assert.IsFalse(wig1.WaitForIdle(200));
Assert.IsFalse(wig2.WaitForIdle(200));
wig1.Start();
Assert.IsTrue(wig1.WaitForIdle(200));
Assert.IsFalse(wig2.WaitForIdle(200));
wig2.Start();
Assert.IsTrue(wig1.WaitForIdle(0));
Assert.IsTrue(wig2.WaitForIdle(200));
}
private object DoWork(object state)
{
Thread.Sleep(100);
return null;
}
}
}
+144
View File
@@ -0,0 +1,144 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
public class CallerState
{
private int _val = 0;
public int Value
{
get { return _val; }
}
protected void IncValue()
{
++_val;
}
}
public class NonDisposableCallerState : CallerState
{
public NonDisposableCallerState()
{
IncValue();
}
}
public class DisposableCallerState : CallerState, IDisposable
{
public DisposableCallerState()
{
IncValue();
}
#region IDisposable Members
public void Dispose()
{
IncValue();
}
#endregion
}
/// <summary>
/// Summary description for StateDisposeExample.
/// </summary>
[TestFixture]
[Category("TestStateDispose")]
public class TestStateDispose
{
public TestStateDispose()
{
}
/// <summary>
/// Example of non disposable caller state
/// </summary>
[Test]
public void DisposeCallerState()
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.DisposeOfStateObjects = true;
SmartThreadPool smartThreadPool = new SmartThreadPool(stpStartInfo);
CallerState nonDisposableCallerState = new NonDisposableCallerState();
CallerState disposableCallerState = new DisposableCallerState();
IWorkItemResult wir1 =
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
nonDisposableCallerState);
IWorkItemResult wir2 =
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
disposableCallerState);
wir1.GetResult();
Assert.AreEqual(1, nonDisposableCallerState.Value);
wir2.GetResult();
// Wait a little bit for the working thread to call dispose on the
// work item's state.
smartThreadPool.WaitForIdle();
Assert.AreEqual(2, disposableCallerState.Value);
smartThreadPool.Shutdown();
}
/// <summary>
/// Example of non disposable caller state
/// </summary>
[Test]
public void DontDisposeCallerState()
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.DisposeOfStateObjects = false;
SmartThreadPool smartThreadPool = new SmartThreadPool(stpStartInfo);
bool success = false;
CallerState nonDisposableCallerState = new NonDisposableCallerState();
CallerState disposableCallerState = new DisposableCallerState();
IWorkItemResult wir1 =
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
nonDisposableCallerState);
IWorkItemResult wir2 =
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
disposableCallerState);
wir1.GetResult();
success = (1 == nonDisposableCallerState.Value);
wir2.GetResult();
success = success && (1 == disposableCallerState.Value);
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
private object DoSomeWork(object state)
{
Thread.Sleep(1000);
return 1;
}
}
}
+65
View File
@@ -0,0 +1,65 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for TestThreadPriority.
/// </summary>
[TestFixture]
[Category("TestThreadPriority")]
public class TestThreadPriority
{
[Test]
public void TestDefaultPriority()
{
SmartThreadPool stp = new SmartThreadPool();
IWorkItemResult wir = stp.QueueWorkItem(new WorkItemCallback(DoSomeWork));
ThreadPriority currentThreadPriority = (ThreadPriority)wir.GetResult();
Assert.AreEqual(currentThreadPriority, SmartThreadPool.DefaultThreadPriority);
}
[Test]
public void TestPriorities()
{
ThreadPriority [] priorities =
{
ThreadPriority.Lowest,
ThreadPriority.BelowNormal,
ThreadPriority.Normal,
ThreadPriority.AboveNormal,
ThreadPriority.Highest,
};
foreach(ThreadPriority priority in priorities)
{
CheckSinglePriority(priority);
}
}
private void CheckSinglePriority(ThreadPriority threadPriority)
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.ThreadPriority = threadPriority;
SmartThreadPool stp = new SmartThreadPool(stpStartInfo);
IWorkItemResult wir = stp.QueueWorkItem(new WorkItemCallback(DoSomeWork));
ThreadPriority currentThreadPriority = (ThreadPriority)wir.GetResult();
Assert.AreEqual(currentThreadPriority, threadPriority);
}
private object DoSomeWork(object state)
{
return Thread.CurrentThread.Priority;
}
}
}
+101
View File
@@ -0,0 +1,101 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace WorkItemsGroupTests
{
/// <summary>
/// Summary description for TestChainedDelegates.
/// </summary>
[TestFixture]
[Category("Test WorkItemsGroup ChainedDelegates")]
public class TestChainedDelegates
{
public TestChainedDelegates()
{
}
[Test]
public void GoodCallback()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
workItemsGroup.QueueWorkItem(new WorkItemCallback(DoWork));
workItemsGroup.WaitForIdle();
smartThreadPool.Shutdown();
}
[Test]
[ExpectedException(typeof(NotSupportedException))]
public void ChainedDelegatesCallback()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
WorkItemCallback workItemCallback = new WorkItemCallback(DoWork);
workItemCallback += new WorkItemCallback(DoWork);
workItemsGroup.QueueWorkItem(workItemCallback);
workItemsGroup.WaitForIdle();
smartThreadPool.Shutdown();
}
[Test]
public void GoodPostExecute()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
workItemsGroup.QueueWorkItem(
new WorkItemCallback(DoWork),
null,
new PostExecuteWorkItemCallback(DoPostExecute));
workItemsGroup.WaitForIdle();
smartThreadPool.Shutdown();
}
[Test]
[ExpectedException(typeof(NotSupportedException))]
public void ChainedDelegatesPostExecute()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
PostExecuteWorkItemCallback postExecuteWorkItemCallback =
new PostExecuteWorkItemCallback(DoPostExecute);
postExecuteWorkItemCallback +=
new PostExecuteWorkItemCallback(DoPostExecute);
workItemsGroup.QueueWorkItem(
new WorkItemCallback(DoWork),
null,
postExecuteWorkItemCallback);
workItemsGroup.WaitForIdle();
smartThreadPool.Shutdown();
}
private object DoWork(object state)
{
return null;
}
private void DoPostExecute(IWorkItemResult wir)
{
}
}
}
+99
View File
@@ -0,0 +1,99 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for TestWIGConcurrency.
/// </summary>
[TestFixture]
[Category("TestWIGConcurrency")]
public class TestWIGConcurrency
{
private Random _randGen;
private int [] _concurrentOps;
private int _concurrencyPerWig;
private bool _success;
public TestWIGConcurrency()
{
}
[Test]
public void TestConcurrencies()
{
Concurrency(1, 1, 10);
Concurrency(1, 1, 100);
Concurrency(1, 5, 10);
Concurrency(1, 5, 100);
Concurrency(5, 5, 10);
Concurrency(5, 5, 100);
}
private void Concurrency(
int concurrencyPerWig,
int wigsCount,
int workItemsCount)
{
Console.WriteLine(
"Testing : concurrencyPerWig = {0}, wigsCount = {1}, workItemsCount = {2}",
concurrencyPerWig,
wigsCount,
workItemsCount);
_success = true;
_concurrencyPerWig = concurrencyPerWig;
_randGen = new Random(0);
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.StartSuspended = true;
SmartThreadPool stp = new SmartThreadPool(stpStartInfo);
_concurrentOps = new int[wigsCount];
IWorkItemsGroup [] wigs = new IWorkItemsGroup[wigsCount];
for(int i = 0; i < wigs.Length; ++i)
{
wigs[i] = stp.CreateWorkItemsGroup(_concurrencyPerWig);
for(int j = 0; j < workItemsCount; ++j)
{
wigs[i].QueueWorkItem(new WorkItemCallback(this.DoWork), i);
}
wigs[i].Start();
}
stp.Start();
stp.WaitForIdle();
Assert.IsTrue(_success);
stp.Shutdown();
}
private object DoWork(object state)
{
int wigsIndex = (int)state;
int val = Interlocked.Increment(ref _concurrentOps[wigsIndex]);
_success = _success && (val <= _concurrencyPerWig);
int waitTime = _randGen.Next(50);
Thread.Sleep(waitTime);
val = Interlocked.Decrement(ref _concurrentOps[wigsIndex]);
_success = _success && (val >= 0);
return null;
}
}
}
+89
View File
@@ -0,0 +1,89 @@
using System;
using NUnit.Framework;
using Amib.Threading;
namespace WorkItemsGroupTests
{
/// <summary>
/// Summary description for TestExceptions.
/// </summary>
[TestFixture]
[Category("Test WorkItemsGroup Exceptions")]
public class TestExceptions
{
private class DivArgs
{
public int x;
public int y;
}
[Test]
public void ExceptionThrowing()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
DivArgs divArgs = new DivArgs();
divArgs.x = 10;
divArgs.y = 0;
IWorkItemResult wir =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoDiv), divArgs);
try
{
wir.GetResult();
}
catch(WorkItemResultException wire)
{
Assert.IsTrue(wire.InnerException is DivideByZeroException);
return;
}
catch(Exception e)
{
e.GetHashCode();
Assert.Fail();
}
Assert.Fail();
}
[Test]
public void ExceptionReturning()
{
bool success = true;
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
DivArgs divArgs = new DivArgs();
divArgs.x = 10;
divArgs.y = 0;
IWorkItemResult wir =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoDiv), divArgs);
Exception e = null;
try
{
wir.GetResult(out e);
}
catch (Exception ex)
{
ex.GetHashCode();
success = false;
}
Assert.IsTrue(success);
Assert.IsTrue(e is DivideByZeroException);
}
private object DoDiv(object state)
{
DivArgs divArgs = (DivArgs)state;
return (divArgs.x / divArgs.y);
}
}
}
+166
View File
@@ -0,0 +1,166 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace WorkItemsGroupTests
{
/// <summary>
/// Summary description for GetResultExample.
/// </summary>
[TestFixture]
[Category("Test WorkItemsGroup GetResult")]
public class TestGetResult
{
/// <summary>
/// Example of how to queue a work item and then wait infinitely for the result.
/// </summary>
[Test]
public void BlockingCall()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = false;
IWorkItemResult wir =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
if (!wir.IsCompleted)
{
int result = (int)wir.GetResult();
success = (1 == result);
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue a work item and then wait on a timeout for the result.
/// </summary>
[Test]
public void Timeout()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = false;
IWorkItemResult wir =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
try
{
wir.GetResult(500, true);
}
catch (WorkItemTimeoutException)
{
success = true;
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue a work item and then cancel it while it is in the queue.
/// </summary>
[Test]
public void WorkItemCanceling()
{
// Create a SmartThreadPool with only one thread.
// It just to show how to use the work item canceling feature
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 1);
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = false;
// Queue a work item that will occupy the thread in the pool
IWorkItemResult wir1 =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
// Queue another work item that will wait for the first to complete
IWorkItemResult wir2 =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
// Wait a while for the thread pool to start executing the first work item
Thread.Sleep(100);
// The first work item cannot be canceled since it is currently executing
if (!wir1.Cancel())
{
// Cancel the second work item while it still in the queue
if (wir2.Cancel())
{
try
{
// Retreiving result of a canceled work item throws an exception
wir2.GetResult();
}
catch (WorkItemCancelException)
{
success = true;
}
}
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to interrupt the waiting for a work item to complete.
/// </summary>
[Test]
public void WorkItemWaitCanceling()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
ManualResetEvent cancelWaitHandle = new ManualResetEvent(false);
bool success = false;
// Queue a work item that will occupy the thread in the pool
IWorkItemResult wir1 =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
// Queue another work item that will wait for the first to complete
IWorkItemResult wir2 =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.SignalCancel), cancelWaitHandle);
try
{
wir1.GetResult(System.Threading.Timeout.Infinite, true, cancelWaitHandle);
}
catch (WorkItemTimeoutException)
{
success = true;
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
private object DoSomeWork(object state)
{
Thread.Sleep(1000);
return 1;
}
private object SignalCancel(object state)
{
ManualResetEvent cancelWaitHandle = state as ManualResetEvent;
Thread.Sleep(250);
cancelWaitHandle.Set();
return null;
}
}
}
+227
View File
@@ -0,0 +1,227 @@
using System;
using System.Diagnostics;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace WorkItemsGroupTests
{
/// <summary>
/// Summary description for MultipleWorkItemsExample.
/// </summary>
[TestFixture]
[Category("Test WorkItemsGroup MultipleWorkItems")]
public class TestMultipleWorkItems
{
/// <summary>
/// Example of how to queue several work items and then wait infinitely for
/// all of them to complete.
/// </summary>
[Test]
public void WaitAll()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = true;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
SmartThreadPool.WaitAll(wirs);
for(int i = 0; i < wirs.Length; ++i)
{
if (!wirs[i].IsCompleted)
{
success = false;
break;
}
else
{
int result = (int)wirs[i].GetResult();
if (1 != result)
{
success = false;
break;
}
}
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue several work items and then wait infinitely for
/// one of them to complete.
///
/// You can use this technique if you have several work items that return the same
/// infomration, but use different method to aquire it. Just execute all of them at
/// once and wait for the first work item to complete.
///
/// For example: You need an information about a person and you can query several
/// information sites (FBI, CIA, etc.). Query all of them at once and use the first
/// answer to arrive.
/// </summary>
[Test]
public void WaitAny()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = false;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
int index = SmartThreadPool.WaitAny(wirs);
if (wirs[index].IsCompleted)
{
int result = (int)wirs[index].GetResult();
if (1 == result)
{
success = true;
}
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue several work items and then wait on a timeout for all
/// of them to complete.
/// </summary>
[Test]
public void WaitAllWithTimeoutSuccess()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = true;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
bool timeout = !SmartThreadPool.WaitAll(wirs, 1500, true);
success = !timeout;
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue several work items and then wait on a timeout for all
/// of them to complete.
/// </summary>
[Test]
public void WaitAllWithTimeoutFailure()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = true;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
bool timeout = !SmartThreadPool.WaitAll(wirs, 10, true);
success = timeout;
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue several work items and then wait on a timeout for any
/// of them to complete.
/// </summary>
[Test]
public void WaitAnyWithTimeoutSuccess()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = true;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
int index = SmartThreadPool.WaitAny(wirs, 1500, true);
success = (index != WaitHandle.WaitTimeout);
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue several work items and then wait on a timeout for any
/// of them to complete.
/// </summary>
[Test]
public void WaitAnyWithTimeoutFailure()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = true;
IWorkItemResult [] wirs = new IWorkItemResult[5];
for(int i = 0; i < wirs.Length; ++i)
{
wirs[i] =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
}
int index = SmartThreadPool.WaitAny(wirs, 10, true);
success = (index == WaitHandle.WaitTimeout);
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
private object DoSomeWork(object state)
{
Thread.Sleep(1000);
return 1;
}
}
}
+231
View File
@@ -0,0 +1,231 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace WorkItemsGroupTests
{
/// <summary>
/// Summary description for DoTestPostExecute.
/// </summary>
[TestFixture]
[Category("WorkItemsGroup")]
public class TestPostExecution
{
/// <summary>
///
/// </summary>
[Test]
public void DefaultPostExecute_AlwaysCall()
{
Assert.IsTrue(DoTestDefaultPostExecute(CallToPostExecute.Always, true));
}
[Test]
public void DefaultPostExecute_NeverCall()
{
Assert.IsTrue(DoTestDefaultPostExecute(CallToPostExecute.Never, false));
}
[Test]
public void DefaultPostExecute_CallWhenCanceled()
{
Assert.IsTrue(DoTestDefaultPostExecute(CallToPostExecute.WhenWorkItemCanceled, false));
}
[Test]
public void DefaultPostExecute_CallWhenNotCanceled()
{
Assert.IsTrue(DoTestDefaultPostExecute(CallToPostExecute.WhenWorkItemNotCanceled, true));
}
/// <summary>
///
/// </summary>
[Test]
public void PostExecute_AlwaysCall()
{
Assert.IsTrue(DoTestPostExecute(CallToPostExecute.Always, true));
}
[Test]
public void PostExecute_NeverCall()
{
Assert.IsTrue(DoTestPostExecute(CallToPostExecute.Never, false));
}
[Test]
public void PostExecute_CallWhenCanceled()
{
Assert.IsTrue(DoTestPostExecute(CallToPostExecute.WhenWorkItemCanceled, false));
}
[Test]
public void PostExecute_CallWhenNotCanceled()
{
Assert.IsTrue(DoTestPostExecute(CallToPostExecute.WhenWorkItemNotCanceled, true));
}
/// <summary>
///
/// </summary>
[Test]
public void PostExecuteWithCancel_AlwaysCall()
{
Assert.IsTrue(DoTestPostExecuteWithCancel(CallToPostExecute.Always, true));
}
[Test]
public void PostExecuteWithCancel_NeverCall()
{
Assert.IsTrue(DoTestPostExecuteWithCancel(CallToPostExecute.Never, false));
}
[Test]
public void PostExecuteWithCancel_CallWhenCanceled()
{
Assert.IsTrue(DoTestPostExecuteWithCancel(CallToPostExecute.WhenWorkItemCanceled, true));
}
[Test]
public void PostExecuteWithCancel_CallWhenNotCanceled()
{
Assert.IsTrue(DoTestPostExecuteWithCancel(CallToPostExecute.WhenWorkItemNotCanceled, false));
}
private class PostExecuteResult
{
public ManualResetEvent wh = new ManualResetEvent(false);
}
/// <summary>
/// Example of how to use the post execute callback
/// </summary>
private bool DoTestDefaultPostExecute(CallToPostExecute callToPostExecute, bool answer)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
WIGStartInfo wigStartInfo = new WIGStartInfo();
wigStartInfo.CallToPostExecute = callToPostExecute;
wigStartInfo.PostExecuteWorkItemCallback = new PostExecuteWorkItemCallback(this.DoSomePostExecuteWork);
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue, wigStartInfo);
bool success = false;
PostExecuteResult postExecuteResult = new PostExecuteResult();
IWorkItemResult wir =
workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
postExecuteResult);
if (!wir.IsCompleted)
{
int result = (int)wir.GetResult();
success = (1 == result);
success = success && (postExecuteResult.wh.WaitOne(1000, true) == answer);
}
smartThreadPool.Shutdown();
return success;
}
/// <summary>
/// Example of how to use the post execute callback
/// </summary>
private bool DoTestPostExecute(CallToPostExecute callToPostExecute, bool answer)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = false;
PostExecuteResult postExecuteResult = new PostExecuteResult();
IWorkItemResult wir =
workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
postExecuteResult,
new PostExecuteWorkItemCallback(this.DoSomePostExecuteWork),
callToPostExecute);
if (!wir.IsCompleted)
{
int result = (int)wir.GetResult();
success = (1 == result);
success = success && (postExecuteResult.wh.WaitOne(1000, true) == answer);
}
smartThreadPool.Shutdown();
return success;
}
/// <summary>
/// Example of how to queue a work item and then cancel it while it is in the queue.
/// </summary>
private bool DoTestPostExecuteWithCancel(CallToPostExecute callToPostExecute, bool answer)
{
// Create a SmartThreadPool with only one thread.
// It just to show how to use the work item canceling feature
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(1);
bool success = false;
PostExecuteResult postExecuteResult = new PostExecuteResult();
// Queue a work item that will occupy the thread in the pool
workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
// Queue another work item that will wait for the first to complete
IWorkItemResult wir =
workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
postExecuteResult,
new PostExecuteWorkItemCallback(this.DoSomePostExecuteWork),
callToPostExecute);
// Wait a while for the thread pool to start executing the first work item
Thread.Sleep(100);
// Cancel the second work item while it still in the queue
if (wir.Cancel())
{
success = (postExecuteResult.wh.WaitOne(1000, true) == answer);
}
smartThreadPool.Shutdown();
return success;
}
private object DoSomeWork(object state)
{
Thread.Sleep(1000);
return 1;
}
private void DoSomePostExecuteWork(IWorkItemResult wir)
{
PostExecuteResult postExecuteResult = wir.State as PostExecuteResult;
postExecuteResult.wh.Set();
}
private object SignalCancel(object state)
{
ManualResetEvent cancelWaitHandle = state as ManualResetEvent;
Thread.Sleep(250);
cancelWaitHandle.Set();
return null;
}
}
}
+148
View File
@@ -0,0 +1,148 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace WorkItemsGroupTests
{
public class CallerState
{
private int _val = 0;
public int Value
{
get { return _val; }
}
protected void IncValue()
{
++_val;
}
}
public class NonDisposableCallerState : CallerState
{
public NonDisposableCallerState()
{
IncValue();
}
}
public class DisposableCallerState : CallerState, IDisposable
{
public DisposableCallerState()
{
IncValue();
}
#region IDisposable Members
public void Dispose()
{
IncValue();
}
#endregion
}
/// <summary>
/// Summary description for StateDisposeExample.
/// </summary>
[TestFixture]
[Category("WorkItemsGroup")]
public class TestStateDispose
{
public TestStateDispose()
{
}
/// <summary>
/// Example of non disposable caller state
/// </summary>
[Test]
public void DisposeCallerState()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
WIGStartInfo wigStartInfo = new WIGStartInfo();
wigStartInfo.DisposeOfStateObjects = true;
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue, wigStartInfo);
CallerState nonDisposableCallerState = new NonDisposableCallerState();
CallerState disposableCallerState = new DisposableCallerState();
IWorkItemResult wir1 =
workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
nonDisposableCallerState);
IWorkItemResult wir2 =
workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
disposableCallerState);
wir1.GetResult();
Assert.AreEqual(1, nonDisposableCallerState.Value);
wir2.GetResult();
// Wait a little bit for the working thread to call dispose on the
// work item's state.
workItemsGroup.WaitForIdle();
Assert.AreEqual(2, disposableCallerState.Value);
smartThreadPool.Shutdown();
}
/// <summary>
/// Example of non disposable caller state
/// </summary>
[Test]
public void DontDisposeCallerState()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
WIGStartInfo wigStartInfo = new WIGStartInfo();
wigStartInfo.DisposeOfStateObjects = false;
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue, wigStartInfo);
bool success = false;
CallerState nonDisposableCallerState = new NonDisposableCallerState();
CallerState disposableCallerState = new DisposableCallerState();
IWorkItemResult wir1 =
workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
nonDisposableCallerState);
IWorkItemResult wir2 =
workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
disposableCallerState);
wir1.GetResult();
success = (1 == nonDisposableCallerState.Value);
wir2.GetResult();
success = success && (1 == disposableCallerState.Value);
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
private object DoSomeWork(object state)
{
Thread.Sleep(1000);
return 1;
}
}
}
+109
View File
@@ -0,0 +1,109 @@
using System;
using System.Threading;
using System.Diagnostics;
using NUnit.Framework;
using Amib.Threading;
namespace WorkItemsGroupTests
{
/// <summary>
/// Summary description for TestWaitForIdle.
/// </summary>
[TestFixture]
[Category("WorkItemsGroup")]
public class TestWaitForIdle
{
public TestWaitForIdle()
{
}
/// <summary>
/// Example of waiting for idle
/// </summary>
[Test]
public void WaitForIdle()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0);
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = false;
for(int i = 0; i < 100; ++i)
{
workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
}
success = !workItemsGroup.WaitForIdle(3500);
success = success && workItemsGroup.WaitForIdle(1000);
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
[Test]
public void WaitForIdleOnSTPThread()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0);
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
IWorkItemResult wir = workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoWaitForIdle),
workItemsGroup);
Exception e;
wir.GetResult(out e);
smartThreadPool.Shutdown();
Assert.IsNotNull(e);
}
[Test]
public void WaitForIdleOnSTPThreadForAnotherWorkItemsGroup()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0);
IWorkItemsGroup workItemsGroup1 = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
IWorkItemsGroup workItemsGroup2 = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
workItemsGroup1.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
workItemsGroup1.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
IWorkItemResult wir = workItemsGroup2.QueueWorkItem(
new WorkItemCallback(this.DoWaitForIdle),
workItemsGroup1);
Exception e;
wir.GetResult(out e);
smartThreadPool.Shutdown();
Assert.IsNull(e);
}
private int x = 0;
private object DoSomeWork(object state)
{
Debug.WriteLine(Interlocked.Increment(ref x));
Thread.Sleep(1000);
return 1;
}
private object DoWaitForIdle(object state)
{
IWorkItemsGroup workItemsGroup = state as IWorkItemsGroup;
workItemsGroup.WaitForIdle();
return null;
}
}
}
+80
View File
@@ -0,0 +1,80 @@
using System;
using System.Threading;
using System.Diagnostics;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for TestWaitForIdle.
/// </summary>
[TestFixture]
[Category("TestWaitForIdle")]
public class TestWaitForIdle
{
public TestWaitForIdle()
{
}
/// <summary>
/// Example of waiting for idle
/// </summary>
[Test]
public void WaitForIdle()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0);
bool success = false;
for(int i = 0; i < 100; ++i)
{
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
}
success = !smartThreadPool.WaitForIdle(3500);
success = success && smartThreadPool.WaitForIdle(1000);
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
[Test]
public void WaitForIdleOnWrongThread()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0);
IWorkItemResult wir = smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoWaitForIdle),
smartThreadPool);
Exception e;
wir.GetResult(out e);
smartThreadPool.Shutdown();
Assert.IsTrue(e is NotSupportedException);
}
private int x = 0;
private object DoSomeWork(object state)
{
Debug.WriteLine(Interlocked.Increment(ref x));
Thread.Sleep(1000);
return 1;
}
private object DoWaitForIdle(object state)
{
SmartThreadPool smartThreadPool = state as SmartThreadPool;
smartThreadPool.WaitForIdle();
return null;
}
}
}
+190
View File
@@ -0,0 +1,190 @@
using System;
using System.Threading;
using System.Diagnostics;
using NUnit.Framework;
using Amib.Threading;
namespace WorkItemsGroupTests
{
/// <summary>
/// Summary description for TestWorkItemsGroups.
/// </summary>
[TestFixture]
[Category("TestWorkItemsGroups")]
public class TestWorkItemsGroups
{
public TestWorkItemsGroups()
{
}
[Test]
public void BlockingCall()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = false;
IWorkItemResult wir =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
if (!wir.IsCompleted)
{
int result = (int)wir.GetResult();
success = (1 == result);
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue a work item and then wait on a timeout for the result.
/// </summary>
[Test]
public void Timeout()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = false;
IWorkItemResult wir =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
try
{
wir.GetResult(500, true);
}
catch (WorkItemTimeoutException)
{
success = true;
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to queue a work item and then cancel it while it is in the queue.
/// </summary>
[Test]
public void WorkItemCanceling()
{
// Create a SmartThreadPool with only one thread.
// It just to show how to use the work item canceling feature
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 1);
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = false;
// Queue a work item that will occupy the thread in the pool
IWorkItemResult wir1 =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
// Queue another work item that will wait for the first to complete
IWorkItemResult wir2 =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
// Wait a while for the thread pool to start executing the first work item
Thread.Sleep(100);
// The first work item cannot be canceled since it is currently executing
if (!wir1.Cancel())
{
// Cancel the second work item while it still in the queue
if (wir2.Cancel())
{
try
{
// Retreiving result of a canceled work item throws an exception
wir2.GetResult();
}
catch (WorkItemCancelException)
{
success = true;
}
}
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
/// <summary>
/// Example of how to interrupt the waiting for a work item to complete.
/// </summary>
[Test]
public void WorkItemWaitCanceling()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
ManualResetEvent cancelWaitHandle = new ManualResetEvent(false);
bool success = false;
// Queue a work item that will occupy the thread in the pool
IWorkItemResult wir1 =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
// Queue another work item that will wait for the first to complete
IWorkItemResult wir2 =
workItemsGroup.QueueWorkItem(new WorkItemCallback(this.SignalCancel), cancelWaitHandle);
try
{
wir1.GetResult(System.Threading.Timeout.Infinite, true, cancelWaitHandle);
}
catch (WorkItemTimeoutException)
{
success = true;
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
private object DoSomeWork(object state)
{
Thread.Sleep(1000);
return 1;
}
private object SignalCancel(object state)
{
ManualResetEvent cancelWaitHandle = state as ManualResetEvent;
Thread.Sleep(250);
cancelWaitHandle.Set();
return null;
}
[Test]
public void Concurrency()
{
}
[Test]
public void WaitForIdle()
{
}
[Test]
public void OnIdleEvent()
{
}
[Test]
public void MultipleGroups()
{
}
}
}
+54
View File
@@ -0,0 +1,54 @@
using System;
using NUnit.Framework;
using Amib.Threading;
using Amib.Threading.Internal;
using SmartThreadPoolTests;
namespace PriorityQueueTests
{
/// <summary>
/// Summary description for TestWorkItemsQueue.
/// </summary>
[TestFixture]
[Category("TestWorkItemsQueue")]
public class TestWorkItemsQueue
{
public TestWorkItemsQueue()
{
}
[Test]
public void Init()
{
}
[Test]
public void IdempotenceWaiterEntry()
{
WorkItemsQueue q = new WorkItemsQueue();
Assert.AreEqual(0, q.WaitersCount);
WorkItemsQueue.WaiterEntry we1 = new Amib.Threading.Internal.WorkItemsQueue.WaiterEntry();
q.PushWaiter(we1);
Assert.AreEqual(1, q.WaitersCount);
q.PushWaiter(we1);
Assert.AreEqual(1, q.WaitersCount);
WorkItemsQueue.WaiterEntry we2 = new Amib.Threading.Internal.WorkItemsQueue.WaiterEntry();
q.PushWaiter(we2);
Assert.AreEqual(2, q.WaitersCount);
q.PushWaiter(we2);
Assert.AreEqual(2, q.WaitersCount);
}
}
}
+43
View File
@@ -0,0 +1,43 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartThreadPool", "SmartThreadPool\SmartThreadPool.csproj", "{8684FC56-A679-4E2E-8F96-E172FB062EB6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STPExamples", "STPExamples\STPExamples.csproj", "{AE943A5A-7CFD-4E0D-BA51-FB763AAEA9A3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STPTests", "STPTests\STPTests.csproj", "{6A3E4DBF-12AD-4636-ACB3-24B5172FAE03}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UsageControl", "UsageControl\UsageControl.csproj", "{C11A4561-CCB5-4C96-8DF2-B804031D89D8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestSmartThreadPool", "TestSmartThreadPool\TestSmartThreadPool.csproj", "{976DB12F-9198-4AD9-981A-1652615C9B0D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8684FC56-A679-4E2E-8F96-E172FB062EB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8684FC56-A679-4E2E-8F96-E172FB062EB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8684FC56-A679-4E2E-8F96-E172FB062EB6}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{8684FC56-A679-4E2E-8F96-E172FB062EB6}.Release|Any CPU.Build.0 = Debug|Any CPU
{AE943A5A-7CFD-4E0D-BA51-FB763AAEA9A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE943A5A-7CFD-4E0D-BA51-FB763AAEA9A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE943A5A-7CFD-4E0D-BA51-FB763AAEA9A3}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{AE943A5A-7CFD-4E0D-BA51-FB763AAEA9A3}.Release|Any CPU.Build.0 = Debug|Any CPU
{6A3E4DBF-12AD-4636-ACB3-24B5172FAE03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A3E4DBF-12AD-4636-ACB3-24B5172FAE03}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A3E4DBF-12AD-4636-ACB3-24B5172FAE03}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{6A3E4DBF-12AD-4636-ACB3-24B5172FAE03}.Release|Any CPU.Build.0 = Debug|Any CPU
{C11A4561-CCB5-4C96-8DF2-B804031D89D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C11A4561-CCB5-4C96-8DF2-B804031D89D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C11A4561-CCB5-4C96-8DF2-B804031D89D8}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{C11A4561-CCB5-4C96-8DF2-B804031D89D8}.Release|Any CPU.Build.0 = Debug|Any CPU
{976DB12F-9198-4AD9-981A-1652615C9B0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{976DB12F-9198-4AD9-981A-1652615C9B0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{976DB12F-9198-4AD9-981A-1652615C9B0D}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{976DB12F-9198-4AD9-981A-1652615C9B0D}.Release|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+61
View File
@@ -0,0 +1,61 @@
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("1.0.*")]
//
// 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("")]
+132
View File
@@ -0,0 +1,132 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using System.Web;
using System.Runtime.Remoting.Messaging;
namespace Amib.Threading
{
#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 MethodInfo getLogicalCallContextMethodInfo =
typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
private static 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);
else // Use the default "HttpContext" slot name
return "HttpContext";
}
#endregion
#region Private fields
private HttpContext _httpContext = null;
private LogicalCallContext _callContext = null;
#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;
}
}
}
#endregion
}
+81
View File
@@ -0,0 +1,81 @@
// Ami Bar
// amibar@gmail.com
using System;
using System.Runtime.Serialization;
namespace Amib.Threading
{
#region Exceptions
/// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
/// </summary>
[Serializable]
public sealed class WorkItemCancelException : ApplicationException
{
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)
{
}
}
/// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
/// </summary>
[Serializable]
public sealed class WorkItemTimeoutException : ApplicationException
{
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)
{
}
}
/// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
/// </summary>
[Serializable]
public sealed class WorkItemResultException : ApplicationException
{
public WorkItemResultException() : base()
{
}
public WorkItemResultException(string message) : base(message)
{
}
public WorkItemResultException(string message, Exception e) : base(message, e)
{
}
public WorkItemResultException(SerializationInfo si, StreamingContext sc) : base(si, sc)
{
}
}
#endregion
}
+269
View File
@@ -0,0 +1,269 @@
// Ami Bar
// amibar@gmail.com
using System;
using System.Threading;
namespace Amib.Threading
{
#region Delegates
/// <summary>
/// A delegate that represents the method to run as the work item
/// </summary>
/// <param name="state">A state object for the method to run</param>
public delegate object WorkItemCallback(object state);
/// <summary>
/// A delegate to call after the WorkItemCallback completed
/// </summary>
/// <param name="wir">The work item result object</param>
public delegate void PostExecuteWorkItemCallback(IWorkItemResult 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);
#endregion
#region WorkItem Priority
public enum WorkItemPriority
{
Lowest,
BelowNormal,
Normal,
AboveNormal,
Highest,
}
#endregion
#region IHasWorkItemPriority interface
public interface IHasWorkItemPriority
{
WorkItemPriority WorkItemPriority { get; }
}
#endregion
#region IWorkItemsGroup interface
/// <summary>
/// IWorkItemsGroup interface
/// </summary>
public interface IWorkItemsGroup
{
/// <summary>
/// Get/Set the name of the WorkItemsGroup
/// </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);
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
void WaitForIdle();
bool WaitForIdle(TimeSpan timeout);
bool WaitForIdle(int millisecondsTimeout);
int WaitingCallbacks { get; }
event WorkItemsGroupIdleHandler OnIdle;
void Cancel();
void Start();
}
#endregion
#region CallToPostExecute enumerator
[Flags]
public enum CallToPostExecute
{
Never = 0x00,
WhenWorkItemCanceled = 0x01,
WhenWorkItemNotCanceled = 0x02,
Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
}
#endregion
#region IWorkItemResult interface
/// <summary>
/// IWorkItemResult interface
/// </summary>
public interface IWorkItemResult
{
/// <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();
/// <summary>
/// Get the result of the work item.
/// If the work item didn't run yet then the caller waits until timeout.
/// </summary>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
object GetResult(
int millisecondsTimeout,
bool exitContext);
/// <summary>
/// Get the result of the work item.
/// If the work item didn't run yet then the caller waits until timeout.
/// </summary>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
object GetResult(
TimeSpan timeout,
bool exitContext);
/// <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.
/// </summary>
/// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
/// <param name="exitContext">
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
/// </param>
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
object GetResult(
int millisecondsTimeout,
bool exitContext,
WaitHandle cancelWaitHandle);
/// <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.
/// </summary>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
object GetResult(
TimeSpan timeout,
bool exitContext,
WaitHandle cancelWaitHandle);
/// <summary>
/// Get the result of the work item.
/// If the work item didn't run yet then the caller waits.
/// </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);
/// <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="e">Filled with the exception if one was thrown</param>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
object GetResult(
int millisecondsTimeout,
bool exitContext,
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="e">Filled with the exception if one was thrown</param>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
object GetResult(
TimeSpan timeout,
bool exitContext,
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 or until the cancelWaitHandle is signaled.
/// </summary>
/// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
/// <param name="exitContext">
/// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false.
/// </param>
/// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</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
/// On cancel throws WorkItemCancelException
object GetResult(
int millisecondsTimeout,
bool exitContext,
WaitHandle cancelWaitHandle,
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 or until the cancelWaitHandle is signaled.
/// </summary>
/// <returns>The result of the work item</returns>
/// <param name="e">Filled with the exception if one was thrown</param>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
object GetResult(
TimeSpan timeout,
bool exitContext,
WaitHandle cancelWaitHandle,
out Exception e);
/// <summary>
/// Gets an indication whether the asynchronous operation has completed.
/// </summary>
bool IsCompleted { get; }
/// <summary>
/// Gets an indication whether the asynchronous operation has been canceled.
/// </summary>
bool IsCanceled { get; }
/// <summary>
/// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
/// </summary>
object State { get; }
/// <summary>
/// Cancel the work item if it didn't start running yet.
/// </summary>
/// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
bool Cancel();
/// <summary>
/// Get the work item's priority
/// </summary>
WorkItemPriority WorkItemPriority { get; }
/// <summary>
/// Return the result, same as GetResult()
/// </summary>
object Result { get; }
/// <summary>
/// Returns the exception if occured otherwise returns null.
/// </summary>
object Exception { get; }
}
#endregion
}
+240
View File
@@ -0,0 +1,240 @@
// Ami Bar
// amibar@gmail.com
using System;
using System.Collections;
using System.Diagnostics;
namespace Amib.Threading.Internal
{
#region PriorityQueue class
/// <summary>
/// PriorityQueue class
/// This class is not thread safe because we use external lock
/// </summary>
public sealed class PriorityQueue : IEnumerable
{
#region Private members
/// <summary>
/// The number of queues, there is one for each type of priority
/// </summary>
private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1;
/// <summary>
/// Work items queues. There is one for each type of priority
/// </summary>
private Queue [] _queues = new Queue[_queuesCount];
/// <summary>
/// The total number of work items within the queues
/// </summary>
private int _workItemsCount = 0;
/// <summary>
/// Use with IEnumerable interface
/// </summary>
private int _version = 0;
#endregion
#region Contructor
public PriorityQueue()
{
for(int i = 0; i < _queues.Length; ++i)
{
_queues[i] = new Queue();
}
}
#endregion
#region Methods
/// <summary>
/// Enqueue a work item.
/// </summary>
/// <param name="workItem">A work item</param>
public void Enqueue(IHasWorkItemPriority workItem)
{
Debug.Assert(null != workItem);
int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1;
Debug.Assert(queueIndex >= 0);
Debug.Assert(queueIndex < _queuesCount);
_queues[queueIndex].Enqueue(workItem);
++_workItemsCount;
++_version;
}
/// <summary>
/// Dequeque a work item.
/// </summary>
/// <returns>Returns the next work item</returns>
public IHasWorkItemPriority Dequeue()
{
IHasWorkItemPriority workItem = null;
if(_workItemsCount > 0)
{
int queueIndex = GetNextNonEmptyQueue(-1);
Debug.Assert(queueIndex >= 0);
workItem = _queues[queueIndex].Dequeue() as IHasWorkItemPriority;
Debug.Assert(null != workItem);
--_workItemsCount;
++_version;
}
return workItem;
}
/// <summary>
/// Find the next non empty queue starting at queue queueIndex+1
/// </summary>
/// <param name="queueIndex">The index-1 to start from</param>
/// <returns>
/// The index of the next non empty queue or -1 if all the queues are empty
/// </returns>
private int GetNextNonEmptyQueue(int queueIndex)
{
for(int i = queueIndex+1; i < _queuesCount; ++i)
{
if(_queues[i].Count > 0)
{
return i;
}
}
return -1;
}
/// <summary>
/// The number of work items
/// </summary>
public int Count
{
get
{
return _workItemsCount;
}
}
/// <summary>
/// Clear all the work items
/// </summary>
public void Clear()
{
if (_workItemsCount > 0)
{
foreach(Queue queue in _queues)
{
queue.Clear();
}
_workItemsCount = 0;
++_version;
}
}
#endregion
#region IEnumerable Members
/// <summary>
/// Returns an enumerator to iterate over the work items
/// </summary>
/// <returns>Returns an enumerator</returns>
public IEnumerator GetEnumerator()
{
return new PriorityQueueEnumerator(this);
}
#endregion
#region PriorityQueueEnumerator
/// <summary>
/// The class the implements the enumerator
/// </summary>
private class PriorityQueueEnumerator : IEnumerator
{
private PriorityQueue _priorityQueue;
private int _version;
private int _queueIndex;
private IEnumerator _enumerator;
public PriorityQueueEnumerator(PriorityQueue priorityQueue)
{
_priorityQueue = priorityQueue;
_version = _priorityQueue._version;
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
if (_queueIndex >= 0)
{
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
}
else
{
_enumerator = null;
}
}
#region IEnumerator Members
public void Reset()
{
_version = _priorityQueue._version;
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
if (_queueIndex >= 0)
{
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
}
else
{
_enumerator = null;
}
}
public object Current
{
get
{
Debug.Assert(null != _enumerator);
return _enumerator.Current;
}
}
public bool MoveNext()
{
if (null == _enumerator)
{
return false;
}
if(_version != _priorityQueue._version)
{
throw new InvalidOperationException("The collection has been modified");
}
if (!_enumerator.MoveNext())
{
_queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex);
if(-1 == _queueIndex)
{
return false;
}
_enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
_enumerator.MoveNext();
return true;
}
return true;
}
#endregion
}
#endregion
}
#endregion
}
+347
View File
@@ -0,0 +1,347 @@
using System;
using System.Diagnostics;
namespace Amib.Threading.Internal
{
internal enum STPPerformanceCounterType
{
// Fields
ActiveThreads = 0,
InUseThreads = 1,
OverheadThreads = 2,
OverheadThreadsPercent = 3,
OverheadThreadsPercentBase = 4,
WorkItems = 5,
WorkItemsInQueue = 6,
WorkItemsProcessed = 7,
WorkItemsQueuedPerSecond = 8,
WorkItemsProcessedPerSecond = 9,
AvgWorkItemWaitTime = 10,
AvgWorkItemWaitTimeBase = 11,
AvgWorkItemProcessTime = 12,
AvgWorkItemProcessTimeBase = 13,
WorkItemsGroups = 14,
LastCounter = 14,
}
/// <summary>
/// Summary description for STPPerformanceCounter.
/// </summary>
internal class STPPerformanceCounter
{
// Fields
private PerformanceCounterType _pcType;
protected string _counterHelp;
protected string _counterName;
// Methods
public STPPerformanceCounter(
string counterName,
string counterHelp,
PerformanceCounterType pcType)
{
this._counterName = counterName;
this._counterHelp = counterHelp;
this._pcType = pcType;
}
public void AddCounterToCollection(CounterCreationDataCollection counterData)
{
CounterCreationData counterCreationData = new CounterCreationData(
_counterName,
_counterHelp,
_pcType);
counterData.Add(counterCreationData);
}
// Properties
public string Name
{
get
{
return _counterName;
}
}
}
internal class STPPerformanceCounters
{
// Fields
internal STPPerformanceCounter[] _stpPerformanceCounters;
private static STPPerformanceCounters _instance;
internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
internal const string _stpCategoryName = "SmartThreadPool";
// Methods
static STPPerformanceCounters()
{
_instance = new STPPerformanceCounters();
}
private STPPerformanceCounters()
{
STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[]
{
new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32),
new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32),
new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32),
new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction),
new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase),
new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32),
new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32),
new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32),
new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32),
new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32),
new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64),
new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase),
new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64),
new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase),
new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32),
};
_stpPerformanceCounters = stpPerformanceCounters;
SetupCategory();
}
private void SetupCategory()
{
if (!PerformanceCounterCategory.Exists(_stpCategoryName))
{
CounterCreationDataCollection counters = new CounterCreationDataCollection();
for (int i = 0; i < _stpPerformanceCounters.Length; i++)
{
_stpPerformanceCounters[i].AddCounterToCollection(counters);
}
PerformanceCounterCategory.Create(
_stpCategoryName,
_stpCategoryHelp,
PerformanceCounterCategoryType.MultiInstance,
counters);
}
}
// Properties
public static STPPerformanceCounters Instance
{
get
{
return _instance;
}
}
}
internal class STPInstancePerformanceCounter : IDisposable
{
// Fields
private PerformanceCounter _pcs;
// Methods
protected STPInstancePerformanceCounter()
{
}
public STPInstancePerformanceCounter(
string instance,
STPPerformanceCounterType spcType)
{
STPPerformanceCounters counters = STPPerformanceCounters.Instance;
_pcs = new PerformanceCounter(
STPPerformanceCounters._stpCategoryName,
counters._stpPerformanceCounters[(int) spcType].Name,
instance,
false);
_pcs.RawValue = _pcs.RawValue;
}
~STPInstancePerformanceCounter()
{
Close();
}
public void Close()
{
if (_pcs != null)
{
_pcs.RemoveInstance();
_pcs.Close();
_pcs = null;
}
}
public void Dispose()
{
Close();
GC.SuppressFinalize(this);
}
public virtual void Increment()
{
_pcs.Increment();
}
public virtual void IncrementBy(long val)
{
_pcs.IncrementBy(val);
}
public virtual void Set(long val)
{
_pcs.RawValue = val;
}
}
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
{
// Fields
private STPInstancePerformanceCounter[] _pcs;
private static STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
// Methods
static STPInstancePerformanceCounters()
{
_stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter();
}
public STPInstancePerformanceCounters(string instance)
{
_pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
STPPerformanceCounters counters = STPPerformanceCounters.Instance;
for (int i = 0; i < _pcs.Length; i++)
{
if (instance != null)
{
_pcs[i] = new STPInstancePerformanceCounter(
instance,
(STPPerformanceCounterType) i);
}
else
{
_pcs[i] = _stpInstanceNullPerformanceCounter;
}
}
}
public void Close()
{
if (null != _pcs)
{
for (int i = 0; i < _pcs.Length; i++)
{
if (null != _pcs[i])
{
_pcs[i].Close();
}
}
_pcs = null;
}
}
~STPInstancePerformanceCounters()
{
Close();
}
public void Dispose()
{
Close();
GC.SuppressFinalize(this);
}
private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
{
return _pcs[(int) spcType];
}
public void SampleThreads(long activeThreads, long inUseThreads)
{
GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads);
GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads);
GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads);
GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads);
GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads);
}
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
{
GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed);
GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued);
GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed);
GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued);
GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed);
}
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
{
GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds);
GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment();
}
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
{
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds);
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
}
}
internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable
{
static NullSTPInstancePerformanceCounters()
{
}
private static NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(null);
public static NullSTPInstancePerformanceCounters Instance
{
get { return _instance; }
}
public NullSTPInstancePerformanceCounters(string instance) {}
public void Close() {}
public void Dispose() {}
public void SampleThreads(long activeThreads, long inUseThreads) {}
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {}
}
}
+89
View File
@@ -0,0 +1,89 @@
// Ami Bar
// amibar@gmail.com
using System.Threading;
namespace Amib.Threading
{
/// <summary>
/// Summary description for STPStartInfo.
/// </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;
/// <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>
/// 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;
public STPStartInfo() : base()
{
_idleTimeout = SmartThreadPool.DefaultIdleTimeout;
_minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
_maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
_threadPriority = SmartThreadPool.DefaultThreadPriority;
_pcInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
}
public STPStartInfo(STPStartInfo stpStartInfo) : base(stpStartInfo)
{
_idleTimeout = stpStartInfo._idleTimeout;
_minWorkerThreads = stpStartInfo._minWorkerThreads;
_maxWorkerThreads = stpStartInfo._maxWorkerThreads;
_threadPriority = stpStartInfo._threadPriority;
_pcInstanceName = stpStartInfo._pcInstanceName;
}
public int IdleTimeout
{
get { return _idleTimeout; }
set { _idleTimeout = value; }
}
public int MinWorkerThreads
{
get { return _minWorkerThreads; }
set { _minWorkerThreads = value; }
}
public int MaxWorkerThreads
{
get { return _maxWorkerThreads; }
set { _maxWorkerThreads = value; }
}
public ThreadPriority ThreadPriority
{
get { return _threadPriority; }
set { _threadPriority = value; }
}
public string PerformanceCounterInstanceName
{
get { return _pcInstanceName; }
set { _pcInstanceName = value; }
}
}
}
File diff suppressed because it is too large Load Diff
+141
View File
@@ -0,0 +1,141 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectType>Local</ProjectType>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{8684FC56-A679-4E2E-8F96-E172FB062EB6}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ApplicationIcon>
</ApplicationIcon>
<AssemblyKeyContainerName>
</AssemblyKeyContainerName>
<AssemblyName>SmartThreadPool</AssemblyName>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
<DefaultClientScript>JScript</DefaultClientScript>
<DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
<DefaultTargetSchema>IE50</DefaultTargetSchema>
<DelaySign>false</DelaySign>
<OutputType>Library</OutputType>
<RootNamespace>SmartThreadPool</RootNamespace>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<StartupObject>
</StartupObject>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>false</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>bin\Release\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>false</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>true</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>none</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System">
<Name>System</Name>
</Reference>
<Reference Include="System.Data">
<Name>System.Data</Name>
</Reference>
<Reference Include="System.Web">
<Name>System.Web</Name>
</Reference>
<Reference Include="System.Xml">
<Name>System.XML</Name>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="CallerThreadContext.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Exceptions.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Interfaces.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="PriorityQueue.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="SmartThreadPool.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="STPPerformanceCounter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="STPStartInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WIGStartInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WorkItem.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WorkItemFactory.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WorkItemInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WorkItemsGroup.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WorkItemsQueue.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
+99
View File
@@ -0,0 +1,99 @@
// Ami Bar
// amibar@gmail.com
namespace Amib.Threading
{
/// <summary>
/// Summary description for WIGStartInfo.
/// </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;
public WIGStartInfo()
{
_useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
_useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
_disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
_callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
_postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
_startSuspended = SmartThreadPool.DefaultStartSuspended;
}
public WIGStartInfo(WIGStartInfo wigStartInfo)
{
_useCallerCallContext = wigStartInfo._useCallerCallContext;
_useCallerHttpContext = wigStartInfo._useCallerHttpContext;
_disposeOfStateObjects = wigStartInfo._disposeOfStateObjects;
_callToPostExecute = wigStartInfo._callToPostExecute;
_postExecuteWorkItemCallback = wigStartInfo._postExecuteWorkItemCallback;
_startSuspended = wigStartInfo._startSuspended;
}
public bool UseCallerCallContext
{
get { return _useCallerCallContext; }
set { _useCallerCallContext = value; }
}
public bool UseCallerHttpContext
{
get { return _useCallerHttpContext; }
set { _useCallerHttpContext = value; }
}
public bool DisposeOfStateObjects
{
get { return _disposeOfStateObjects; }
set { _disposeOfStateObjects = value; }
}
public CallToPostExecute CallToPostExecute
{
get { return _callToPostExecute; }
set { _callToPostExecute = value; }
}
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
{
get { return _postExecuteWorkItemCallback; }
set { _postExecuteWorkItemCallback = value; }
}
public bool StartSuspended
{
get { return _startSuspended; }
set { _startSuspended = value; }
}
}
}
File diff suppressed because it is too large Load Diff
+333
View File
@@ -0,0 +1,333 @@
// Ami Bar
// amibar@gmail.com
using System;
namespace Amib.Threading.Internal
{
#region WorkItemFactory class
public class WorkItemFactory
{
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="callback">A callback to execute</param>
/// <returns>Returns a work item</returns>
public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemCallback callback)
{
return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null);
}
/// <summary>
/// Create a new work item
/// </summary>
/// <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>
/// <returns>Returns a work item</returns>
public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemCallback callback,
WorkItemPriority workItemPriority)
{
return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority);
}
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="workItemInfo">Work item info</param>
/// <param name="callback">A callback to execute</param>
/// <returns>Returns a work item</returns>
public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemInfo workItemInfo,
WorkItemCallback callback)
{
return CreateWorkItem(
workItemsGroup,
wigStartInfo,
workItemInfo,
callback,
null);
}
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start 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</returns>
public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemCallback callback,
object state)
{
ValidateCallback(callback);
WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
WorkItem workItem = new WorkItem(
workItemsGroup,
workItemInfo,
callback,
state);
return workItem;
}
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start 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>
/// <param name="workItemPriority">The work item priority</param>
/// <returns>Returns a work item</returns>
public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemCallback callback,
object state,
WorkItemPriority workItemPriority)
{
ValidateCallback(callback);
WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
workItemInfo.WorkItemPriority = workItemPriority;
WorkItem workItem = new WorkItem(
workItemsGroup,
workItemInfo,
callback,
state);
return workItem;
}
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start information</param>
/// <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</returns>
public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemInfo workItemInfo,
WorkItemCallback callback,
object state)
{
ValidateCallback(callback);
ValidateCallback(workItemInfo.PostExecuteWorkItemCallback);
WorkItem workItem = new WorkItem(
workItemsGroup,
new WorkItemInfo(workItemInfo),
callback,
state);
return workItem;
}
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start 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>
/// <param name="postExecuteWorkItemCallback">
/// A delegate to call after the callback completion
/// </param>
/// <returns>Returns a work item</returns>
public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemCallback callback,
object state,
PostExecuteWorkItemCallback postExecuteWorkItemCallback)
{
ValidateCallback(callback);
ValidateCallback(postExecuteWorkItemCallback);
WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
WorkItem workItem = new WorkItem(
workItemsGroup,
workItemInfo,
callback,
state);
return workItem;
}
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start 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>
/// <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</returns>
public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemCallback callback,
object state,
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
WorkItemPriority workItemPriority)
{
ValidateCallback(callback);
ValidateCallback(postExecuteWorkItemCallback);
WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
workItemInfo.WorkItemPriority = workItemPriority;
WorkItem workItem = new WorkItem(
workItemsGroup,
workItemInfo,
callback,
state);
return workItem;
}
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start 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>
/// <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</returns>
public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemCallback callback,
object state,
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
CallToPostExecute callToPostExecute)
{
ValidateCallback(callback);
ValidateCallback(postExecuteWorkItemCallback);
WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
workItemInfo.CallToPostExecute = callToPostExecute;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
WorkItem workItem = new WorkItem(
workItemsGroup,
workItemInfo,
callback,
state);
return workItem;
}
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start 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>
/// <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</returns>
public static WorkItem CreateWorkItem(
IWorkItemsGroup workItemsGroup,
WIGStartInfo wigStartInfo,
WorkItemCallback callback,
object state,
PostExecuteWorkItemCallback postExecuteWorkItemCallback,
CallToPostExecute callToPostExecute,
WorkItemPriority workItemPriority)
{
ValidateCallback(callback);
ValidateCallback(postExecuteWorkItemCallback);
WorkItemInfo workItemInfo = new WorkItemInfo();
workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
workItemInfo.CallToPostExecute = callToPostExecute;
workItemInfo.WorkItemPriority = workItemPriority;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
WorkItem workItem = new WorkItem(
workItemsGroup,
workItemInfo,
callback,
state);
return workItem;
}
private static void ValidateCallback(Delegate callback)
{
if(callback.GetInvocationList().Length > 1)
{
throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
}
}
}
#endregion
}
+102
View File
@@ -0,0 +1,102 @@
// Ami Bar
// amibar@gmail.com
namespace Amib.Threading
{
#region WorkItemInfo class
/// <summary>
/// Summary description for WorkItemInfo.
/// </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;
}
public WorkItemInfo(WorkItemInfo workItemInfo)
{
_useCallerCallContext = workItemInfo._useCallerCallContext;
_useCallerHttpContext = workItemInfo._useCallerHttpContext;
_disposeOfStateObjects = workItemInfo._disposeOfStateObjects;
_callToPostExecute = workItemInfo._callToPostExecute;
_postExecuteWorkItemCallback = workItemInfo._postExecuteWorkItemCallback;
_workItemPriority = workItemInfo._workItemPriority;
}
public bool UseCallerCallContext
{
get { return _useCallerCallContext; }
set { _useCallerCallContext = value; }
}
public bool UseCallerHttpContext
{
get { return _useCallerHttpContext; }
set { _useCallerHttpContext = value; }
}
public bool DisposeOfStateObjects
{
get { return _disposeOfStateObjects; }
set { _disposeOfStateObjects = value; }
}
public CallToPostExecute CallToPostExecute
{
get { return _callToPostExecute; }
set { _callToPostExecute = value; }
}
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
{
get { return _postExecuteWorkItemCallback; }
set { _postExecuteWorkItemCallback = value; }
}
public WorkItemPriority WorkItemPriority
{
get { return _workItemPriority; }
set { _workItemPriority = value; }
}
}
#endregion
}
+512
View File
@@ -0,0 +1,512 @@
// Ami Bar
// amibar@gmail.com
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 : IWorkItemsGroup
{
#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";
/// <summary>
/// A reference to the SmartThreadPool instance that created this
/// WorkItemsGroup.
/// </summary>
private SmartThreadPool _stp;
/// <summary>
/// The OnIdle event
/// </summary>
private event WorkItemsGroupIdleHandler _onIdle;
/// <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 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 WIGStartInfo _workItemsGroupStartInfo;
/// <summary>
/// Signaled when all of the WorkItemsGroup's work item completed.
/// </summary>
private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(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", concurrency, "concurrency must be greater than zero");
}
_stp = stp;
_concurrency = concurrency;
_workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo);
_workItemsQueue = new PriorityQueue();
// The _workItemsInStpQueue gets the number of currently executing work items,
// because once a work item is executing, it cannot be cancelled.
_workItemsInStpQueue = _workItemsExecutingInStp;
}
#endregion
#region IWorkItemsGroup implementation
/// <summary>
/// Get/Set the name of the SmartThreadPool instance
/// </summary>
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
/// <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, _workItemsGroupStartInfo, callback);
EnqueueToSTPNextWorkItem(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)
{
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, workItemPriority);
EnqueueToSTPNextWorkItem(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)
{
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)
{
_canceledWorkItemsGroup.IsCanceled = true;
_workItemsQueue.Clear();
_workItemsInStpQueue = 0;
_canceledWorkItemsGroup = new CanceledWorkItemsGroup();
}
}
public void Start()
{
lock (this)
{
if (!_workItemsGroupStartInfo.StartSuspended)
{
return;
}
_workItemsGroupStartInfo.StartSuspended = false;
}
for(int i = 0; i < _concurrency; ++i)
{
EnqueueToSTPNextWorkItem(null, false);
}
}
#endregion
#region Private methods
private void RegisterToWorkItemCompletion(IWorkItemResult wir)
{
IInternalWorkItemResult iwir = wir as IInternalWorkItemResult;
iwir.OnWorkItemStarted += new WorkItemStateCallback(OnWorkItemStartedCallback);
iwir.OnWorkItemCompleted += new WorkItemStateCallback(OnWorkItemCompletedCallback);
}
public void OnSTPIsStarting()
{
lock (this)
{
if (_workItemsGroupStartInfo.StartSuspended)
{
return;
}
}
for(int i = 0; i < _concurrency; ++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);
}
// Ignore exceptions
catch{}
}
}
private void OnWorkItemStartedCallback(WorkItem workItem)
{
lock(_lock)
{
++_workItemsExecutingInStp;
}
}
private void OnWorkItemCompletedCallback(WorkItem workItem)
{
EnqueueToSTPNextWorkItem(null, true);
}
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);
Trace.WriteLine("WorkItemsGroup " + Name + " is NOT idle");
_isIdleWaitHandle.Reset();
}
}
// If the work items queue of the group is empty than quit
if (0 == _workItemsQueue.Count)
{
if (0 == _workItemsInStpQueue)
{
_stp.UnregisterWorkItemsGroup(this);
Trace.WriteLine("WorkItemsGroup " + Name + " is idle");
_isIdleWaitHandle.Set();
_stp.QueueWorkItem(new WorkItemCallback(this.FireOnIdle));
}
return;
}
if (!_workItemsGroupStartInfo.StartSuspended)
{
if (_workItemsInStpQueue < _concurrency)
{
WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
_stp.Enqueue(nextWorkItem, true);
++_workItemsInStpQueue;
}
}
}
}
#endregion
}
#endregion
}
+600
View File
@@ -0,0 +1,600 @@
// Ami Bar
// amibar@gmail.com
using System;
using System.Threading;
namespace Amib.Threading.Internal
{
#region WorkItemsQueue class
/// <summary>
/// WorkItemsQueue class.
/// </summary>
public class WorkItemsQueue : IDisposable
{
#region Member variables
/// <summary>
/// Waiters queue (implemented as stack).
/// </summary>
private WaiterEntry _headWaiterEntry = new WaiterEntry();
/// <summary>
/// Waiters count
/// </summary>
private int _waitersCount = 0;
/// <summary>
/// Work items queue
/// </summary>
private PriorityQueue _workItems = new PriorityQueue();
/// <summary>
/// Indicate that work items are allowed to be queued
/// </summary>
private bool _isWorkItemsQueueActive = true;
/// <summary>
/// Each thread in the thread pool keeps its own waiter entry.
/// </summary>
[ThreadStatic]
private static WaiterEntry _waiterEntry;
/// <summary>
/// A flag that indicates if the WorkItemsQueue has been disposed.
/// </summary>
private bool _isDisposed = false;
#endregion
#region Public properties
/// <summary>
/// Returns the current number of work items in the queue
/// </summary>
public int Count
{
get
{
lock(this)
{
ValidateNotDisposed();
return _workItems.Count;
}
}
}
/// <summary>
/// Returns the current number of waiters
/// </summary>
public int WaitersCount
{
get
{
lock(this)
{
ValidateNotDisposed();
return _waitersCount;
}
}
}
#endregion
#region Public methods
/// <summary>
/// Enqueue a work item to the queue.
/// </summary>
public bool EnqueueWorkItem(WorkItem workItem)
{
// A work item cannot be null, since null is used in the
// WaitForWorkItem() method to indicate timeout or cancel
if (null == workItem)
{
throw new ArgumentNullException("workItem" , "workItem cannot be null");
}
bool enqueue = true;
// First check if there is a waiter waiting for work item. During
// the check, timed out waiters are ignored. If there is no
// waiter then the work item is queued.
lock(this)
{
ValidateNotDisposed();
if (!_isWorkItemsQueueActive)
{
return false;
}
while(_waitersCount > 0)
{
// Dequeue a waiter.
WaiterEntry waiterEntry = PopWaiter();
// Signal the waiter. On success break the loop
if (waiterEntry.Signal(workItem))
{
enqueue = false;
break;
}
}
if (enqueue)
{
// Enqueue the work item
_workItems.Enqueue(workItem);
}
}
return true;
}
/// <summary>
/// Waits for a work item or exits on timeout or cancel
/// </summary>
/// <param name="millisecondsTimeout">Timeout in milliseconds</param>
/// <param name="cancelEvent">Cancel wait handle</param>
/// <returns>Returns true if the resource was granted</returns>
public WorkItem DequeueWorkItem(
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.
WaiterEntry waiterEntry = null;
WorkItem workItem = null;
lock(this)
{
ValidateNotDisposed();
// If there are waiting work items then take one and return.
if (_workItems.Count > 0)
{
workItem = _workItems.Dequeue() as WorkItem;
return workItem;
}
// No waiting work items ...
else
{
// Get the wait 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 [] {
waiterEntry.WaitHandle,
cancelEvent };
// Wait for an available resource, cancel event, or timeout.
// 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.
int index = WaitHandle.WaitAny(
waitHandles,
millisecondsTimeout,
true);
lock(this)
{
// success is true if it got a work item.
bool success = (0 == index);
// The timeout variable is used only for readability.
// (We treat cancel as timeout)
bool timeout = !success;
// On timeout update the waiterEntry that it is timed out
if (timeout)
{
// The Timeout() fails if the waiter has already been signaled
timeout = waiterEntry.Timeout();
// On timeout remove the waiter from the queue.
// Note that the complexity is O(1).
if(timeout)
{
RemoveWaiter(waiterEntry, false);
}
// Again readability
success = !timeout;
}
// On success return the work item
if (success)
{
workItem = waiterEntry.WorkItem;
if (null == workItem)
{
workItem = _workItems.Dequeue() as WorkItem;
}
}
}
// On failure return null.
return workItem;
}
/// <summary>
/// Cleanup the work items queue, hence no more work
/// items are allowed to be queue
/// </summary>
protected virtual void Cleanup()
{
lock(this)
{
// Deactivate only once
if (!_isWorkItemsQueueActive)
{
return;
}
// Don't queue more work items
_isWorkItemsQueueActive = false;
foreach(WorkItem workItem in _workItems)
{
workItem.DisposeOfState();
}
// Clear the work items that are already queued
_workItems.Clear();
// Note:
// I don't iterate over the queue and dispose of work items's states,
// since if a work item has a state object that is still in use in the
// application then I must not dispose it.
// Tell the waiters that they were timed out.
// It won't signal them to exit, but to ignore their
// next work item.
while(_waitersCount > 0)
{
WaiterEntry waiterEntry = PopWaiter();
waiterEntry.Timeout();
}
}
}
#endregion
#region Private methods
/// <summary>
/// Returns the WaiterEntry of the current thread
/// </summary>
/// <returns></returns>
/// In order to avoid creation and destuction of WaiterEntry
/// objects each thread has its own WaiterEntry object.
private WaiterEntry GetThreadWaiterEntry()
{
if (null == _waiterEntry)
{
_waiterEntry = new WaiterEntry();
}
_waiterEntry.Reset();
return _waiterEntry;
}
#region Waiters stack methods
/// <summary>
/// Push a new waiter into the waiter's stack
/// </summary>
/// <param name="newWaiterEntry">A waiter to put in the stack</param>
public void PushWaiter(WaiterEntry newWaiterEntry)
{
// Remove the waiter if it is already in the stack and
// update waiter's count as needed
RemoveWaiter(newWaiterEntry, false);
// If the stack is empty then newWaiterEntry is the new head of the stack
if (null == _headWaiterEntry._nextWaiterEntry)
{
_headWaiterEntry._nextWaiterEntry = newWaiterEntry;
newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
}
// If the stack is not empty then put newWaiterEntry as the new head
// of the stack.
else
{
// Save the old first waiter entry
WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
// Update the links
_headWaiterEntry._nextWaiterEntry = newWaiterEntry;
newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry;
newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
}
// Increment the number of waiters
++_waitersCount;
}
/// <summary>
/// Pop a waiter from the waiter's stack
/// </summary>
/// <returns>Returns the first waiter in the stack</returns>
private WaiterEntry PopWaiter()
{
// Store the current stack head
WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
// Store the new stack head
WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry;
// Update the old stack head list links and decrement the number
// waiters.
RemoveWaiter(oldFirstWaiterEntry, true);
// Update the new stack head
_headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry;
if (null != newHeadWaiterEntry)
{
newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry;
}
// Return the old stack head
return oldFirstWaiterEntry;
}
/// <summary>
/// Remove a waiter from the stack
/// </summary>
/// <param name="waiterEntry">A waiter entry to remove</param>
/// <param name="popDecrement">If true the waiter count is always decremented</param>
private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
{
// Store the prev entry in the list
WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;
// Store the next entry in the list
WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;
// A flag to indicate if we need to decrement the waiters count.
// If we got here from PopWaiter then we must decrement.
// If we got here from PushWaiter then we decrement only if
// the waiter was already in the stack.
bool decrementCounter = popDecrement;
// Null the waiter's entry links
waiterEntry._prevWaiterEntry = null;
waiterEntry._nextWaiterEntry = null;
// If the waiter entry had a prev link then update it.
// It also means that the waiter is already in the list and we
// need to decrement the waiters count.
if (null != prevWaiterEntry)
{
prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
decrementCounter = true;
}
// If the waiter entry had a next link then update it.
// It also means that the waiter is already in the list and we
// need to decrement the waiters count.
if (null != nextWaiterEntry)
{
nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
decrementCounter = true;
}
// Decrement the waiters count if needed
if (decrementCounter)
{
--_waitersCount;
}
}
#endregion
#endregion
#region WaiterEntry class
// A waiter entry in the _waiters queue.
public 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);
/// <summary>
/// Flag to know if this waiter already quited from the queue
/// because of a timeout.
/// </summary>
private bool _isTimedout = false;
/// <summary>
/// Flag to know if the waiter was signaled and got a work item.
/// </summary>
private bool _isSignaled = false;
/// <summary>
/// A work item that passed directly to the waiter withou going
/// through the queue
/// </summary>
private WorkItem _workItem = null;
private bool _isDisposed = false;
// Linked list members
internal WaiterEntry _nextWaiterEntry = null;
internal WaiterEntry _prevWaiterEntry = null;
#endregion
#region Construction
public WaiterEntry()
{
Reset();
}
#endregion
#region Public methods
public WaitHandle WaitHandle
{
get { return _waitHandle; }
}
public WorkItem WorkItem
{
get
{
lock(this)
{
return _workItem;
}
}
}
/// <summary>
/// Signal the waiter that it got a work item.
/// </summary>
/// <returns>Return true on success</returns>
/// The method fails if Timeout() preceded its call
public bool Signal(WorkItem workItem)
{
lock(this)
{
if (!_isTimedout)
{
_workItem = workItem;
_isSignaled = true;
_waitHandle.Set();
return true;
}
}
return false;
}
/// <summary>
/// Mark the wait entry that it has been timed out
/// </summary>
/// <returns>Return true on success</returns>
/// The method fails if Signal() preceded its call
public bool Timeout()
{
lock(this)
{
// Time out can happen only if the waiter wasn't marked as
// signaled
if (!_isSignaled)
{
// We don't remove the waiter from the queue, the DequeueWorkItem
// method skips _waiters that were timed out.
_isTimedout = true;
return true;
}
}
return false;
}
/// <summary>
/// Reset the wait entry so it can be used again
/// </summary>
public void Reset()
{
_workItem = null;
_isTimedout = false;
_isSignaled = false;
_waitHandle.Reset();
}
/// <summary>
/// Free resources
/// </summary>
public void Close()
{
if (null != _waitHandle)
{
_waitHandle.Close();
_waitHandle = null;
}
}
#endregion
#region IDisposable Members
public void Dispose()
{
if (!_isDisposed)
{
Close();
_isDisposed = true;
}
}
~WaiterEntry()
{
Dispose();
}
#endregion
}
#endregion
#region IDisposable Members
public void Dispose()
{
if (!_isDisposed)
{
Cleanup();
_isDisposed = true;
GC.SuppressFinalize(this);
}
}
~WorkItemsQueue()
{
Cleanup();
}
private void ValidateNotDisposed()
{
if(_isDisposed)
{
throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
}
}
#endregion
}
#endregion
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+58
View File
@@ -0,0 +1,58 @@
using System.Reflection;
using System.Runtime.CompilerServices;
//
// 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("")]
//
// 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("1.0.*")]
//
// 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("")]
+786
View File
@@ -0,0 +1,786 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using Amib.Threading;
namespace TestSmartThreadPool
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnStart;
private System.Windows.Forms.Button btnStop;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label lblThreadInUse;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.NumericUpDown spinIdleTimeout;
private System.Windows.Forms.NumericUpDown spinMaxThreads;
private System.Windows.Forms.NumericUpDown spinMinThreads;
private System.Windows.Forms.NumericUpDown spinInterval;
private System.Windows.Forms.Timer timerPoll;
private System.ComponentModel.IContainer components;
private System.Windows.Forms.Label lblThreadsInPool;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.NumericUpDown spinConsumingTime;
private SmartThreadPool _smartThreadPool;
private IWorkItemsGroup _workItemsGroup;
private System.Windows.Forms.Label lblWaitingCallbacks;
private System.Windows.Forms.Label label9;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.Label lblWorkItemsGenerated;
private bool running;
private long workItemsGenerated;
private System.Windows.Forms.Label label10;
private System.Windows.Forms.Label lblWorkItemsCompleted;
private UsageControl.UsageControl usageThreadsInPool;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.GroupBox groupBox3;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.GroupBox groupBox4;
private UsageControl.UsageHistoryControl usageHistorySTP;
private System.Diagnostics.PerformanceCounter pcActiveThreads;
private System.Diagnostics.PerformanceCounter pcInUseThreads;
private System.Diagnostics.PerformanceCounter pcQueuedWorkItems;
private System.Diagnostics.PerformanceCounter pcCompletedWorkItems;
private long workItemsCompleted;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
this.btnStart = new System.Windows.Forms.Button();
this.btnStop = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.lblThreadsInPool = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.spinIdleTimeout = new System.Windows.Forms.NumericUpDown();
this.spinMaxThreads = new System.Windows.Forms.NumericUpDown();
this.spinMinThreads = new System.Windows.Forms.NumericUpDown();
this.spinInterval = new System.Windows.Forms.NumericUpDown();
this.lblThreadInUse = new System.Windows.Forms.Label();
this.label7 = new System.Windows.Forms.Label();
this.timerPoll = new System.Windows.Forms.Timer(this.components);
this.spinConsumingTime = new System.Windows.Forms.NumericUpDown();
this.label6 = new System.Windows.Forms.Label();
this.lblWaitingCallbacks = new System.Windows.Forms.Label();
this.label9 = new System.Windows.Forms.Label();
this.label8 = new System.Windows.Forms.Label();
this.label10 = new System.Windows.Forms.Label();
this.lblWorkItemsGenerated = new System.Windows.Forms.Label();
this.lblWorkItemsCompleted = new System.Windows.Forms.Label();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.usageThreadsInPool = new UsageControl.UsageControl();
this.groupBox4 = new System.Windows.Forms.GroupBox();
this.usageHistorySTP = new UsageControl.UsageHistoryControl();
this.pcActiveThreads = new System.Diagnostics.PerformanceCounter();
this.pcInUseThreads = new System.Diagnostics.PerformanceCounter();
this.pcQueuedWorkItems = new System.Diagnostics.PerformanceCounter();
this.pcCompletedWorkItems = new System.Diagnostics.PerformanceCounter();
((System.ComponentModel.ISupportInitialize)(this.spinIdleTimeout)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.spinMaxThreads)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.spinMinThreads)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.spinInterval)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.spinConsumingTime)).BeginInit();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.groupBox1.SuspendLayout();
this.groupBox4.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pcActiveThreads)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pcInUseThreads)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pcQueuedWorkItems)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pcCompletedWorkItems)).BeginInit();
this.SuspendLayout();
//
// btnStart
//
this.btnStart.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnStart.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.btnStart.Location = new System.Drawing.Point(432, 352);
this.btnStart.Name = "btnStart";
this.btnStart.Size = new System.Drawing.Size(72, 24);
this.btnStart.TabIndex = 0;
this.btnStart.Text = "Start";
this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
//
// btnStop
//
this.btnStop.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnStop.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.btnStop.Location = new System.Drawing.Point(520, 352);
this.btnStop.Name = "btnStop";
this.btnStop.Size = new System.Drawing.Size(72, 24);
this.btnStop.TabIndex = 1;
this.btnStop.Text = "Stop";
this.btnStop.Click += new System.EventHandler(this.btnStop_Click);
//
// label1
//
this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label1.Location = new System.Drawing.Point(104, 256);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(104, 24);
this.label1.TabIndex = 2;
this.label1.Text = "Minimum Threads";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// label3
//
this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label3.Location = new System.Drawing.Point(104, 288);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(104, 24);
this.label3.TabIndex = 4;
this.label3.Text = "Maximum Threads";
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// label4
//
this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label4.Location = new System.Drawing.Point(104, 320);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(120, 24);
this.label4.TabIndex = 5;
this.label4.Text = "Idle timeout (Seconds)";
this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// label2
//
this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label2.Location = new System.Drawing.Point(8, 16);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(72, 24);
this.label2.TabIndex = 3;
this.label2.Text = "In pool (Red)";
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblThreadsInPool
//
this.lblThreadsInPool.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.lblThreadsInPool.Location = new System.Drawing.Point(80, 16);
this.lblThreadsInPool.Name = "lblThreadsInPool";
this.lblThreadsInPool.Size = new System.Drawing.Size(80, 24);
this.lblThreadsInPool.TabIndex = 11;
this.lblThreadsInPool.Text = "XXXXXXXXX";
this.lblThreadsInPool.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label5
//
this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label5.Location = new System.Drawing.Point(336, 258);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(280, 24);
this.label5.TabIndex = 12;
this.label5.Text = "Interval between work item production (milliseconds)";
this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// spinIdleTimeout
//
this.spinIdleTimeout.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.spinIdleTimeout.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.spinIdleTimeout.Location = new System.Drawing.Point(8, 320);
this.spinIdleTimeout.Minimum = new System.Decimal(new int[] {
1,
0,
0,
0});
this.spinIdleTimeout.Name = "spinIdleTimeout";
this.spinIdleTimeout.Size = new System.Drawing.Size(88, 29);
this.spinIdleTimeout.TabIndex = 15;
this.spinIdleTimeout.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.spinIdleTimeout.Value = new System.Decimal(new int[] {
10,
0,
0,
0});
//
// spinMaxThreads
//
this.spinMaxThreads.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.spinMaxThreads.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.spinMaxThreads.Location = new System.Drawing.Point(8, 288);
this.spinMaxThreads.Minimum = new System.Decimal(new int[] {
1,
0,
0,
0});
this.spinMaxThreads.Name = "spinMaxThreads";
this.spinMaxThreads.Size = new System.Drawing.Size(88, 29);
this.spinMaxThreads.TabIndex = 14;
this.spinMaxThreads.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.spinMaxThreads.Value = new System.Decimal(new int[] {
10,
0,
0,
0});
this.spinMaxThreads.ValueChanged += new System.EventHandler(this.spinMaxThreads_ValueChanged);
//
// spinMinThreads
//
this.spinMinThreads.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.spinMinThreads.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.spinMinThreads.Location = new System.Drawing.Point(8, 256);
this.spinMinThreads.Name = "spinMinThreads";
this.spinMinThreads.Size = new System.Drawing.Size(88, 29);
this.spinMinThreads.TabIndex = 13;
this.spinMinThreads.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.spinMinThreads.ValueChanged += new System.EventHandler(this.spinMinThreads_ValueChanged);
//
// spinInterval
//
this.spinInterval.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.spinInterval.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.spinInterval.Increment = new System.Decimal(new int[] {
100,
0,
0,
0});
this.spinInterval.Location = new System.Drawing.Point(240, 256);
this.spinInterval.Maximum = new System.Decimal(new int[] {
100000,
0,
0,
0});
this.spinInterval.Name = "spinInterval";
this.spinInterval.Size = new System.Drawing.Size(88, 29);
this.spinInterval.TabIndex = 16;
this.spinInterval.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.spinInterval.Value = new System.Decimal(new int[] {
100,
0,
0,
0});
//
// lblThreadInUse
//
this.lblThreadInUse.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.lblThreadInUse.Location = new System.Drawing.Point(80, 40);
this.lblThreadInUse.Name = "lblThreadInUse";
this.lblThreadInUse.Size = new System.Drawing.Size(80, 24);
this.lblThreadInUse.TabIndex = 18;
this.lblThreadInUse.Text = "XXXXXXXXX";
this.lblThreadInUse.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label7
//
this.label7.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label7.Location = new System.Drawing.Point(8, 40);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(80, 24);
this.label7.TabIndex = 17;
this.label7.Text = "Used (Green)";
this.label7.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// timerPoll
//
this.timerPoll.Interval = 500;
this.timerPoll.Tick += new System.EventHandler(this.timer1_Tick);
//
// spinConsumingTime
//
this.spinConsumingTime.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.spinConsumingTime.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.spinConsumingTime.Increment = new System.Decimal(new int[] {
100,
0,
0,
0});
this.spinConsumingTime.Location = new System.Drawing.Point(240, 288);
this.spinConsumingTime.Maximum = new System.Decimal(new int[] {
100000,
0,
0,
0});
this.spinConsumingTime.Name = "spinConsumingTime";
this.spinConsumingTime.Size = new System.Drawing.Size(88, 29);
this.spinConsumingTime.TabIndex = 20;
this.spinConsumingTime.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.spinConsumingTime.Value = new System.Decimal(new int[] {
100,
0,
0,
0});
//
// label6
//
this.label6.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.label6.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label6.Location = new System.Drawing.Point(336, 290);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(216, 24);
this.label6.TabIndex = 19;
this.label6.Text = "Work item consuming time (milliseconds)";
this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblWaitingCallbacks
//
this.lblWaitingCallbacks.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.lblWaitingCallbacks.Location = new System.Drawing.Point(64, 16);
this.lblWaitingCallbacks.Name = "lblWaitingCallbacks";
this.lblWaitingCallbacks.Size = new System.Drawing.Size(80, 24);
this.lblWaitingCallbacks.TabIndex = 22;
this.lblWaitingCallbacks.Text = "XXXXXXXXX";
this.lblWaitingCallbacks.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label9
//
this.label9.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label9.Location = new System.Drawing.Point(8, 16);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(48, 24);
this.label9.TabIndex = 21;
this.label9.Text = "Queued";
this.label9.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// label8
//
this.label8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label8.Location = new System.Drawing.Point(8, 40);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(64, 24);
this.label8.TabIndex = 25;
this.label8.Text = "Generated";
this.label8.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// label10
//
this.label10.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label10.Location = new System.Drawing.Point(8, 64);
this.label10.Name = "label10";
this.label10.Size = new System.Drawing.Size(64, 24);
this.label10.TabIndex = 26;
this.label10.Text = "Completed";
this.label10.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// lblWorkItemsGenerated
//
this.lblWorkItemsGenerated.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.lblWorkItemsGenerated.Location = new System.Drawing.Point(64, 40);
this.lblWorkItemsGenerated.Name = "lblWorkItemsGenerated";
this.lblWorkItemsGenerated.Size = new System.Drawing.Size(80, 24);
this.lblWorkItemsGenerated.TabIndex = 27;
this.lblWorkItemsGenerated.Text = "XXXXXXXXX";
this.lblWorkItemsGenerated.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// lblWorkItemsCompleted
//
this.lblWorkItemsCompleted.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.lblWorkItemsCompleted.Location = new System.Drawing.Point(64, 64);
this.lblWorkItemsCompleted.Name = "lblWorkItemsCompleted";
this.lblWorkItemsCompleted.Size = new System.Drawing.Size(80, 24);
this.lblWorkItemsCompleted.TabIndex = 28;
this.lblWorkItemsCompleted.Text = "XXXXXXXXX";
this.lblWorkItemsCompleted.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// groupBox2
//
this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.groupBox2.Controls.Add(this.lblWaitingCallbacks);
this.groupBox2.Controls.Add(this.label9);
this.groupBox2.Controls.Add(this.label8);
this.groupBox2.Controls.Add(this.label10);
this.groupBox2.Controls.Add(this.lblWorkItemsGenerated);
this.groupBox2.Controls.Add(this.lblWorkItemsCompleted);
this.groupBox2.Location = new System.Drawing.Point(8, 144);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(152, 96);
this.groupBox2.TabIndex = 33;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Work items";
//
// groupBox3
//
this.groupBox3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.groupBox3.Controls.Add(this.lblThreadInUse);
this.groupBox3.Controls.Add(this.label7);
this.groupBox3.Controls.Add(this.lblThreadsInPool);
this.groupBox3.Controls.Add(this.label2);
this.groupBox3.Location = new System.Drawing.Point(176, 144);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(168, 72);
this.groupBox3.TabIndex = 34;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Threads";
//
// groupBox1
//
this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.groupBox1.Controls.Add(this.usageThreadsInPool);
this.groupBox1.Location = new System.Drawing.Point(8, 8);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(80, 128);
this.groupBox1.TabIndex = 35;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "STP Usage";
//
// usageThreadsInPool
//
this.usageThreadsInPool.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.usageThreadsInPool.BackColor = System.Drawing.Color.Black;
this.usageThreadsInPool.Location = new System.Drawing.Point(20, 16);
this.usageThreadsInPool.Maximum = 25;
this.usageThreadsInPool.Name = "usageThreadsInPool";
this.usageThreadsInPool.Size = new System.Drawing.Size(41, 104);
this.usageThreadsInPool.TabIndex = 37;
this.usageThreadsInPool.Value1 = 1;
this.usageThreadsInPool.Value2 = 24;
//
// groupBox4
//
this.groupBox4.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupBox4.Controls.Add(this.usageHistorySTP);
this.groupBox4.Location = new System.Drawing.Point(104, 8);
this.groupBox4.Name = "groupBox4";
this.groupBox4.Size = new System.Drawing.Size(494, 128);
this.groupBox4.TabIndex = 36;
this.groupBox4.TabStop = false;
this.groupBox4.Text = "STP Usage History";
//
// usageHistorySTP
//
this.usageHistorySTP.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.usageHistorySTP.BackColor = System.Drawing.Color.Black;
this.usageHistorySTP.Location = new System.Drawing.Point(8, 16);
this.usageHistorySTP.Maximum = 100;
this.usageHistorySTP.Name = "usageHistorySTP";
this.usageHistorySTP.Size = new System.Drawing.Size(480, 104);
this.usageHistorySTP.TabIndex = 0;
//
// pcActiveThreads
//
this.pcActiveThreads.CategoryName = "SmartThreadPool";
this.pcActiveThreads.CounterName = "Active threads";
this.pcActiveThreads.InstanceName = "Test SmartThreadPool";
//
// pcInUseThreads
//
this.pcInUseThreads.CategoryName = "SmartThreadPool";
this.pcInUseThreads.CounterName = "In use threads";
this.pcInUseThreads.InstanceName = "Test SmartThreadPool";
//
// pcQueuedWorkItems
//
this.pcQueuedWorkItems.CategoryName = "SmartThreadPool";
this.pcQueuedWorkItems.CounterName = "Work Items in queue";
this.pcQueuedWorkItems.InstanceName = "Test SmartThreadPool";
//
// pcCompletedWorkItems
//
this.pcCompletedWorkItems.CategoryName = "SmartThreadPool";
this.pcCompletedWorkItems.CounterName = "Work Items processed";
this.pcCompletedWorkItems.InstanceName = "Test SmartThreadPool";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(608, 382);
this.Controls.Add(this.groupBox4);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.spinConsumingTime);
this.Controls.Add(this.label6);
this.Controls.Add(this.spinInterval);
this.Controls.Add(this.spinIdleTimeout);
this.Controls.Add(this.spinMaxThreads);
this.Controls.Add(this.spinMinThreads);
this.Controls.Add(this.label5);
this.Controls.Add(this.label4);
this.Controls.Add(this.label3);
this.Controls.Add(this.label1);
this.Controls.Add(this.btnStop);
this.Controls.Add(this.btnStart);
this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MinimumSize = new System.Drawing.Size(616, 416);
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Test Smart Thread Pool";
this.Closing += new System.ComponentModel.CancelEventHandler(this.Form1_Closing);
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.spinIdleTimeout)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.spinMaxThreads)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.spinMinThreads)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.spinInterval)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.spinConsumingTime)).EndInit();
this.groupBox2.ResumeLayout(false);
this.groupBox3.ResumeLayout(false);
this.groupBox1.ResumeLayout(false);
this.groupBox4.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pcActiveThreads)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pcInUseThreads)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pcQueuedWorkItems)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pcCompletedWorkItems)).EndInit();
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
bool runApplication = InitializePerformanceCounters();
if (!runApplication)
{
return;
}
Application.Run(new Form1());
}
// This method is a work around for the Peformance Counter issue.
// When the first SmartThreadPool is created with a Peformance
// Counter name on a machine, it creates the SmartThreadPool
// Peformance Counter category. In this demo I use thes Performance
// Counters to update the GUI.
// The issue is that if this demo runs for the first time on the
// machine, it creates the Peformance Counter category and then
// uses it.
// I don't know why, but every time the demo runs for the first
// time on a machine, it fails to connect to the Peformance Counters,
// because it can't find the Peformance Counter category.
// The work around is to check if the category exists, and if not
// create a SmartThreadPool instance that will create the category.
// After that I spawn another process that runs the demo.
// I tried the another work around and thats to check for the category
// existance, run a second process that will create the category,
// and then continue with the first process, but it doesn't work.
// Thank you for reading the whole comment. If you have another way
// to solve this issue please contact me: amibar@gmail.com.
private static bool InitializePerformanceCounters()
{
if (!PerformanceCounterCategory.Exists("SmartThreadPool"))
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.PerformanceCounterInstanceName = "Test SmartThreadPool";
SmartThreadPool stp = new SmartThreadPool(stpStartInfo);
stp.Shutdown();
if (!PerformanceCounterCategory.Exists("SmartThreadPool"))
{
MessageBox.Show("Failed to create Performance Counters.", "Test Smart Thread Pool", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
Process process = new Process();
process.StartInfo.FileName = Application.ExecutablePath;
try
{
process.Start();
}
catch(Exception e)
{
e.GetHashCode();
MessageBox.Show("If this is the first time you get this message,\r\nplease try to run the demo again.", "Test Smart Thread Pool");
}
return false;
}
return true;
}
private Thread workItemsProducerThread;
private void btnStart_Click(object sender, System.EventArgs e)
{
UpdateControls(true);
workItemsCompleted = 0;
workItemsGenerated = 0;
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.IdleTimeout = Convert.ToInt32(spinIdleTimeout.Value)*1000;
stpStartInfo.MaxWorkerThreads = Convert.ToInt32(spinMaxThreads.Value);
stpStartInfo.MinWorkerThreads = Convert.ToInt32(spinMinThreads.Value);
stpStartInfo.PerformanceCounterInstanceName = "Test SmartThreadPool";
_smartThreadPool = new SmartThreadPool(stpStartInfo);
//_workItemsGroup = _smartThreadPool.CreateWorkItemsGroup(1);
_workItemsGroup = _smartThreadPool;
workItemsProducerThread = new Thread(new ThreadStart(this.WorkItemsProducer));
workItemsProducerThread.IsBackground = true;
workItemsProducerThread.Start();
}
private void btnStop_Click(object sender, System.EventArgs e)
{
running = false;
workItemsProducerThread.Join();
_smartThreadPool.Shutdown();
_smartThreadPool.Dispose();
_smartThreadPool = null;
GC.Collect();
GC.WaitForPendingFinalizers();
UpdateControls(false);
}
private void Form1_Load(object sender, System.EventArgs e)
{
UpdateControls(false);
}
private void UpdateControls(bool start)
{
running = start;
spinMinThreads.Enabled = !start;
spinMaxThreads.Enabled = !start;
spinIdleTimeout.Enabled = !start;
btnStart.Enabled = !start;
btnStop.Enabled = start;
timerPoll.Enabled = start;
lblThreadInUse.Text = "0";
lblThreadsInPool.Text = "0";
lblWaitingCallbacks.Text = "0";
usageThreadsInPool.Maximum = Convert.ToInt32(spinMaxThreads.Value);
usageThreadsInPool.Value1 = 0;
usageThreadsInPool.Value2 = 0;
lblWorkItemsCompleted.Text = "0";
lblWorkItemsGenerated.Text = "0";
usageHistorySTP.Reset();
usageHistorySTP.Maximum = usageThreadsInPool.Maximum;
}
private void spinMinThreads_ValueChanged(object sender, System.EventArgs e)
{
if (spinMinThreads.Value > spinMaxThreads.Value)
{
spinMaxThreads.Value = spinMinThreads.Value;
}
}
private void spinMaxThreads_ValueChanged(object sender, System.EventArgs e)
{
if (spinMaxThreads.Value < spinMinThreads.Value)
{
spinMinThreads.Value = spinMaxThreads.Value;
}
usageThreadsInPool.Maximum = Convert.ToInt32(spinMaxThreads.Value);
}
private void timer1_Tick(object sender, System.EventArgs e)
{
SmartThreadPool stp = _smartThreadPool;
if (null == stp)
{
return;
}
int threadsInUse = (int)pcInUseThreads.NextValue();
int threadsInPool = (int)pcActiveThreads.NextValue();
lblThreadInUse.Text = threadsInUse.ToString();
lblThreadsInPool.Text = threadsInPool.ToString();
lblWaitingCallbacks.Text = pcQueuedWorkItems.NextValue().ToString(); //stp.WaitingCallbacks.ToString();
usageThreadsInPool.Value1 = threadsInUse;
usageThreadsInPool.Value2 = threadsInPool;
lblWorkItemsCompleted.Text = pcCompletedWorkItems.NextValue().ToString();
lblWorkItemsGenerated.Text = workItemsGenerated.ToString();
usageHistorySTP.AddValues(threadsInUse, threadsInPool);
}
private void WorkItemsProducer()
{
WorkItemCallback workItemCallback = new WorkItemCallback(this.DoWork);
while(running)
{
IWorkItemsGroup workItemsGroup = _workItemsGroup;
if (null == workItemsGroup)
{
return;
}
try
{
workItemCallback = new WorkItemCallback(this.DoWork);
workItemsGroup.QueueWorkItem(workItemCallback);
}
catch(ObjectDisposedException e)
{
e.GetHashCode();
break;
}
workItemsGenerated++;
Thread.Sleep(Convert.ToInt32(spinInterval.Value));
}
}
private object DoWork(object obj)
{
Thread.Sleep(Convert.ToInt32(spinConsumingTime.Value));
Interlocked.Increment(ref workItemsCompleted);
return null;
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (null != _smartThreadPool)
{
_smartThreadPool.Shutdown();
_smartThreadPool = null;
_workItemsGroup = null;
}
}
}
}
+485
View File
@@ -0,0 +1,485 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used forserialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="btnStart.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="btnStart.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="btnStart.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="btnStop.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="btnStop.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="btnStop.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label1.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="label1.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label1.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label3.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="label3.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label3.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label4.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="label4.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label4.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label2.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="label2.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label2.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="lblThreadsInPool.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="lblThreadsInPool.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="lblThreadsInPool.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label5.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="label5.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label5.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="spinIdleTimeout.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="spinIdleTimeout.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="spinIdleTimeout.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="spinMaxThreads.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="spinMaxThreads.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="spinMaxThreads.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="spinMinThreads.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="spinMinThreads.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="spinMinThreads.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="spinInterval.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="spinInterval.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="spinInterval.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="lblThreadInUse.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="lblThreadInUse.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="lblThreadInUse.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label7.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="label7.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label7.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="timerPoll.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="timerPoll.Location" type="System.Drawing.Point, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</data>
<data name="timerPoll.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="spinConsumingTime.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="spinConsumingTime.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="spinConsumingTime.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label6.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="label6.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label6.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="lblWaitingCallbacks.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="lblWaitingCallbacks.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="lblWaitingCallbacks.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label9.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="label9.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label9.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label8.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="label8.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label8.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label10.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="label10.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="label10.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="lblWorkItemsGenerated.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="lblWorkItemsGenerated.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="lblWorkItemsGenerated.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="lblWorkItemsCompleted.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="lblWorkItemsCompleted.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="lblWorkItemsCompleted.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="groupBox2.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="groupBox2.GridSize" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>8, 8</value>
</data>
<data name="groupBox2.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="groupBox2.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="groupBox2.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="groupBox2.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="groupBox3.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="groupBox3.GridSize" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>8, 8</value>
</data>
<data name="groupBox3.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="groupBox3.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="groupBox3.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="groupBox3.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="groupBox1.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="groupBox1.GridSize" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>8, 8</value>
</data>
<data name="groupBox1.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="groupBox1.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="groupBox1.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="groupBox1.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="usageThreadsInPool.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="usageThreadsInPool.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="usageThreadsInPool.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="groupBox4.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="groupBox4.GridSize" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>8, 8</value>
</data>
<data name="groupBox4.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="groupBox4.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="groupBox4.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="groupBox4.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="usageHistorySTP.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="usageHistorySTP.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="usageHistorySTP.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="pcActiveThreads.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="pcActiveThreads.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="pcActiveThreads.Location" type="System.Drawing.Point, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>112, 17</value>
</data>
<data name="pcInUseThreads.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="pcInUseThreads.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="pcInUseThreads.Location" type="System.Drawing.Point, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>245, 17</value>
</data>
<data name="pcQueuedWorkItems.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="pcQueuedWorkItems.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="pcQueuedWorkItems.Location" type="System.Drawing.Point, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>377, 17</value>
</data>
<data name="pcCompletedWorkItems.Modifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="pcCompletedWorkItems.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="pcCompletedWorkItems.Location" type="System.Drawing.Point, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>533, 17</value>
</data>
<data name="$this.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>(Default)</value>
</data>
<data name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.Localizable" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.GridSize" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>8, 8</value>
</data>
<data name="$this.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.TrayHeight" type="System.Int32, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>59</value>
</data>
<data name="$this.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.Name">
<value>Form1</value>
</data>
<data name="$this.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAIAICAQAAAAAADoAgAAJgAAABAQEAAAAAAAKAEAAA4DAAAoAAAAIAAAAEAAAAABAAQAAAAAAAAC
AAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/
AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3d3d3d3d3d3d3d3dwBEREREREREREREREREREcAT/
+q///6r///qv////9HAE//qv//+q///6r/////RwBP/6r///qv//+q/////0cAT/+q///6r///qv////
9HAE//+q///6r///qv////RwBP//qv//+q///6r////0cAT//6r///qv//+q////9HAE//+q///6r///
qv////RwBP/6r///qv//+q/////0cAT/+q///6r///qv////9HAE//qv//+q///6r/////RwBP/6r///
qv//+q/////0cAT//6r///qv//+q////9HAE//+q///6r///qv////RwBP//qv//+q///6r////0cAT/
/6r///qv//+q////9HAE//////////////////RwBP/////////////////0cASIiIiIiIiIiIiIiIiI
hHAERERERERERERERERERERwBExMTExMTExMTE7Ozkl0cATMzMzMzMzMzMzMzMzMxAAARERERERERERE
REREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////
/////////////8AAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAA
AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAABgAAAA8AAAAf/////////////
//8oAAAAEAAAACAAAAABAAQAAAAAAIAAAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAA
AACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAA////AAAACqAACqAACqqpmgCp
mqCgAJAKCgAJCqmZAAmpAACZkAAAAKkAAACQAAAAkAAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAVQ
AAUABQAAUAUABQAFAAAAVQAFAAVVAFUAAAUABQBQUAUABQAFAFAFUAVVVQVVAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAAnu8AAG7vAADO4wAAPu0AAG7tAACYIwAA//8AAA==
</value>
</data>
</root>
@@ -0,0 +1,121 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectType>Local</ProjectType>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{976DB12F-9198-4AD9-981A-1652615C9B0D}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ApplicationIcon>App.ico</ApplicationIcon>
<AssemblyKeyContainerName>
</AssemblyKeyContainerName>
<AssemblyName>TestSmartThreadPool</AssemblyName>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
<DefaultClientScript>JScript</DefaultClientScript>
<DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
<DefaultTargetSchema>IE50</DefaultTargetSchema>
<DelaySign>false</DelaySign>
<OutputType>WinExe</OutputType>
<RootNamespace>TestSmartThreadPool</RootNamespace>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<StartupObject>TestSmartThreadPool.Form1</StartupObject>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>false</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>bin\Release\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>false</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>true</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>none</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System">
<Name>System</Name>
</Reference>
<Reference Include="System.Data">
<Name>System.Data</Name>
</Reference>
<Reference Include="System.Drawing">
<Name>System.Drawing</Name>
</Reference>
<Reference Include="System.Windows.Forms">
<Name>System.Windows.Forms</Name>
</Reference>
<Reference Include="System.Xml">
<Name>System.XML</Name>
</Reference>
<ProjectReference Include="..\SmartThreadPool\SmartThreadPool.csproj">
<Name>SmartThreadPool</Name>
<Project>{8684FC56-A679-4E2E-8F96-E172FB062EB6}</Project>
<Package>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Package>
</ProjectReference>
<ProjectReference Include="..\UsageControl\UsageControl.csproj">
<Name>UsageControl</Name>
<Project>{C11A4561-CCB5-4C96-8DF2-B804031D89D8}</Project>
<Package>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</Package>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="App.ico" />
<Compile Include="AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
+58
View File
@@ -0,0 +1,58 @@
using System.Reflection;
using System.Runtime.CompilerServices;
//
// 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("")]
//
// 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("1.0.*")]
//
// 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("")]
+327
View File
@@ -0,0 +1,327 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Windows.Forms;
namespace UsageControl
{
/// <summary>
/// Summary description for UsageControl.
/// </summary>
public class UsageControl : System.Windows.Forms.UserControl
{
private System.ComponentModel.IContainer components = null;
private const int ovalWidth = 18;
private const int columns = 2;
private int fixedWidth;
private int rows = 1;
private int min = 0; // Minimum value for progress range
private int max = 100; // Maximum value for progress range
private int val1 = 0; // Current progress
private int val2 = 0; // Current progress
public UsageControl()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
EnableDoubleBuffering();
fixedWidth = 2 + (ovalWidth+1)*columns + 1;
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
private void EnableDoubleBuffering()
{
// Set the value of the double-buffering style bits to true.
this.SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint,
true);
this.UpdateStyles();
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// UsageControl
//
this.BackColor = System.Drawing.Color.Black;
this.Name = "UsageControl";
this.Size = new System.Drawing.Size(192, 160);
}
#endregion
protected override void OnResize(EventArgs e)
{
Width = fixedWidth;
rows = (ClientRectangle.Height / 4) - 1;
// Invalidate the control to get a repaint.
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
int percent1 = ((val1 - min) * 100) / (max - min);
int percent2 = ((val2 - min) * 100) / (max - min);
int filledCount1 = (rows * percent1) / 100;
int filledCount2 = (rows * percent2) / 100;
int diff = Math.Abs(filledCount1 - filledCount2);
int emptyCount = rows - Math.Max(filledCount1, filledCount2);
int i = 0;
for(i = 0; i < filledCount1; ++i)
{
for(int j = 0; j < columns; ++j)
{
DrawOval(
g,
Pens.LawnGreen,
2 + j*(1+ovalWidth),
ClientRectangle.Bottom - 5 - i*4);
}
}
for(; i < filledCount2; ++i)
{
for(int j = 0; j < columns; ++j)
{
DrawOval(
g,
Pens.Red,
2 + j*(1+ovalWidth),
ClientRectangle.Bottom - 5 - i*4);
}
}
for(; i < rows; ++i)
{
for(int j = 0; j < columns; ++j)
{
DrawOval(
g,
Pens.Green,
2 + j*(1+ovalWidth),
ClientRectangle.Bottom - 5 - i*4);
}
}
// Draw a three-dimensional border around the control.
Draw3DBorder(g);
// Clean up.
//g.Dispose();
base.OnPaint (e);
}
private void DrawOval(Graphics g, Pen pen, int x, int y)
{
g.DrawLine(pen, x+1 , y, x+ovalWidth-2, y);
g.DrawLine(pen, x, y+1, x+ovalWidth-1, y+1);
g.DrawLine(pen, x+1, y+2, x+ovalWidth-2, y+2);
}
public int Maximum
{
get
{
return max;
}
set
{
// Make sure that the maximum value is never set lower than the minimum value.
if (value < min)
{
min = value;
}
max = value;
// Make sure that value is still in range.
if (val1 > max)
{
val1 = max;
}
// Invalidate the control to get a repaint.
this.Invalidate();
}
}
public int Value1
{
get
{
return val1;
}
set
{
int oldValue = val1;
// Make sure that the value does not stray outside the valid range.
if (value < min)
{
val1 = min;
}
else if (value > max)
{
val1 = max;
}
else
{
val1 = value;
}
Invalidate();
/*
// Invalidate only the changed area.
float percent;
Rectangle newValueRect = this.ClientRectangle;
Rectangle oldValueRect = this.ClientRectangle;
// Use a new value to calculate the rectangle for progress.
percent = (float)(val1 - min) / (float)(max - min);
newValueRect.Width = (int)((float)newValueRect.Width * percent);
// Use an old value to calculate the rectangle for progress.
percent = (float)(oldValue - min) / (float)(max - min);
oldValueRect.Width = (int)((float)oldValueRect.Width * percent);
Rectangle updateRect = new Rectangle();
// Find only the part of the screen that must be updated.
if (newValueRect.Width > oldValueRect.Width)
{
updateRect.X = oldValueRect.Size.Width;
updateRect.Width = newValueRect.Width - oldValueRect.Width;
}
else
{
updateRect.X = newValueRect.Size.Width;
updateRect.Width = oldValueRect.Width - newValueRect.Width;
}
updateRect.Height = this.Height;
// Invalidate the intersection region only.
this.Invalidate(updateRect);
*/
}
}
public int Value2
{
get
{
return val2;
}
set
{
int oldValue = val2;
// Make sure that the value does not stray outside the valid range.
if (value < min)
{
val2 = min;
}
else if (value > max)
{
val2 = max;
}
else
{
val2 = value;
}
Invalidate();
/*
// Invalidate only the changed area.
float percent;
Rectangle newValueRect = this.ClientRectangle;
Rectangle oldValueRect = this.ClientRectangle;
// Use a new value to calculate the rectangle for progress.
percent = (float)(val1 - min) / (float)(max - min);
newValueRect.Width = (int)((float)newValueRect.Width * percent);
// Use an old value to calculate the rectangle for progress.
percent = (float)(oldValue - min) / (float)(max - min);
oldValueRect.Width = (int)((float)oldValueRect.Width * percent);
Rectangle updateRect = new Rectangle();
// Find only the part of the screen that must be updated.
if (newValueRect.Width > oldValueRect.Width)
{
updateRect.X = oldValueRect.Size.Width;
updateRect.Width = newValueRect.Width - oldValueRect.Width;
}
else
{
updateRect.X = newValueRect.Size.Width;
updateRect.Width = oldValueRect.Width - newValueRect.Width;
}
updateRect.Height = this.Height;
// Invalidate the intersection region only.
this.Invalidate(updateRect);
*/
}
}
private void Draw3DBorder(Graphics g)
{
int PenWidth = (int)Pens.White.Width;
g.DrawLine(Pens.DarkGray,
new Point(this.ClientRectangle.Left, this.ClientRectangle.Top),
new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Top));
g.DrawLine(Pens.DarkGray,
new Point(this.ClientRectangle.Left, this.ClientRectangle.Top),
new Point(this.ClientRectangle.Left, this.ClientRectangle.Height - PenWidth));
g.DrawLine(Pens.White,
new Point(this.ClientRectangle.Left, this.ClientRectangle.Height - PenWidth),
new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Height - PenWidth));
g.DrawLine(Pens.White,
new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Top),
new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Height - PenWidth));
}
}
}
+119
View File
@@ -0,0 +1,119 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectType>Local</ProjectType>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{C11A4561-CCB5-4C96-8DF2-B804031D89D8}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ApplicationIcon>
</ApplicationIcon>
<AssemblyKeyContainerName>
</AssemblyKeyContainerName>
<AssemblyName>UsageControl</AssemblyName>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
<DefaultClientScript>JScript</DefaultClientScript>
<DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
<DefaultTargetSchema>IE50</DefaultTargetSchema>
<DelaySign>false</DelaySign>
<OutputType>Library</OutputType>
<RootNamespace>UsageControl</RootNamespace>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<StartupObject>
</StartupObject>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>false</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>bin\Release\</OutputPath>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<BaseAddress>285212672</BaseAddress>
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>false</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
</NoWarn>
<Optimize>true</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>none</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System">
<Name>System</Name>
</Reference>
<Reference Include="System.Data">
<Name>System.Data</Name>
</Reference>
<Reference Include="System.Drawing">
<Name>System.Drawing</Name>
</Reference>
<Reference Include="System.Windows.Forms">
<Name>System.Windows.Forms</Name>
</Reference>
<Reference Include="System.Xml">
<Name>System.XML</Name>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="UsageControl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="UsageHistoryControl.cs">
<SubType>UserControl</SubType>
</Compile>
<EmbeddedResource Include="UsageControl.resx">
<DependentUpon>UsageControl.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="UsageHistoryControl.resx">
<DependentUpon>UsageHistoryControl.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
+130
View File
@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used forserialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.TrayHeight" type="System.Int32, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>80</value>
</data>
<data name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>(Default)</value>
</data>
<data name="$this.Localizable" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.Name">
<value>UsageControl</value>
</data>
<data name="$this.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="$this.GridSize" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>8, 8</value>
</data>
</root>
+191
View File
@@ -0,0 +1,191 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
namespace UsageControl
{
/// <summary>
/// Summary description for UsageHistoryControl.
/// </summary>
public class UsageHistoryControl : System.Windows.Forms.UserControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private const int squareWidth = 12;
private const int maxLastValuesCount = 2000;
private const int shiftStep = 3;
private int shift = 0;
private int [] lastValues1 = new int[maxLastValuesCount];
private int [] lastValues2 = new int[maxLastValuesCount];
private int nextValueIndex;
private int lastValuesCount;
private int max = 100;
private int min = 0;
public UsageHistoryControl()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
EnableDoubleBuffering();
Reset();
}
public void Reset()
{
lastValues1.Initialize();
lastValues2.Initialize();
nextValueIndex = 0;
lastValuesCount = 0;
Invalidate();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// UsageHistoryControl
//
this.BackColor = System.Drawing.Color.Black;
this.Name = "UsageHistoryControl";
}
#endregion
private void EnableDoubleBuffering()
{
// Set the value of the double-buffering style bits to true.
this.SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint,
true);
this.UpdateStyles();
}
protected override void OnResize(EventArgs e)
{
// Invalidate the control to get a repaint.
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
for(int i = 0; i <= ClientRectangle.Width+squareWidth; i += squareWidth)
{
g.DrawLine(Pens.Green, i-shift, 0, i-shift, ClientRectangle.Height);
}
for(int i = 0; i < ClientRectangle.Height; i += squareWidth)
{
g.DrawLine(Pens.Green, 0, i, ClientRectangle.Width, i);
}
int startValueIndex = (nextValueIndex-1+maxLastValuesCount)%maxLastValuesCount;
int prevVal1 = GetRelativeValue(lastValues1[startValueIndex]);
int prevVal2 = GetRelativeValue(lastValues2[startValueIndex]);
for(int i = 1; i < lastValuesCount; ++i)
{
int index = nextValueIndex - 1 - i;
if (index < 0)
{
index += maxLastValuesCount;
}
int val1 = GetRelativeValue(lastValues1[index]);
int val2 = GetRelativeValue(lastValues2[index]);
g.DrawLine(
Pens.Red,
ClientRectangle.Width-(i-1)*shiftStep, ClientRectangle.Height-prevVal2,
ClientRectangle.Width-i*shiftStep, ClientRectangle.Height-val2);
g.DrawLine(
Pens.LawnGreen,
ClientRectangle.Width-(i-1)*shiftStep, ClientRectangle.Height-prevVal1,
ClientRectangle.Width-i*shiftStep, ClientRectangle.Height-val1);
prevVal1 = val1;
prevVal2 = val2;
}
}
private int GetRelativeValue(int val)
{
int result = val * (ClientRectangle.Height-2) / max + 1;
return result;
}
public void AddValues(int val1, int val2)
{
lastValues1[nextValueIndex] = val1;
lastValues2[nextValueIndex] = val2;
nextValueIndex++;
nextValueIndex %= maxLastValuesCount;
lastValuesCount++;
if (lastValuesCount > maxLastValuesCount)
{
lastValuesCount = maxLastValuesCount;
}
shift += shiftStep;
shift %= squareWidth;
Invalidate();
}
public int Maximum
{
get
{
return max;
}
set
{
// Make sure that the maximum value is never set lower than the minimum value.
if (value < min)
{
min = value;
}
max = value;
// Invalidate the control to get a repaint.
this.Invalidate();
}
}
}
}
+130
View File
@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used forserialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.Name">
<value>UsageHistoryControl</value>
</data>
<data name="$this.TrayHeight" type="System.Int32, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>80</value>
</data>
<data name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>(Default)</value>
</data>
<data name="$this.Localizable" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="$this.GridSize" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>8, 8</value>
</data>
</root>