mirror of
https://github.com/farcasclaudiu/SmartThreadPool.git
synced 2026-06-28 11:01:04 +03:00
v1.0
SmartThreadPool v1.0
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -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("")]
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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("")]
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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("")]
|
||||||
@@ -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
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
@@ -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>
|
||||||
@@ -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
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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 |
@@ -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("")]
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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("")]
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
Reference in New Issue
Block a user