mirror of
https://github.com/farcasclaudiu/SmartThreadPool.git
synced 2026-06-22 09:01:19 +03:00
v1.0
SmartThreadPool v1.0
This commit is contained in:
+27
-27
@@ -1,28 +1,28 @@
|
||||
|
||||
#ignore thumbnails created by windows
|
||||
Thumbs.db
|
||||
#Ignore files build by Visual Studio
|
||||
*.obj
|
||||
*.exe
|
||||
*.pdb
|
||||
*.user
|
||||
*.aps
|
||||
*.pch
|
||||
*.vspscc
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ncb
|
||||
*.suo
|
||||
*.tlb
|
||||
*.tlh
|
||||
*.bak
|
||||
*.cache
|
||||
*.log
|
||||
[Bb]in
|
||||
[Dd]ebug*/
|
||||
*.lib
|
||||
*.sbr
|
||||
obj/
|
||||
[Rr]elease*/
|
||||
_ReSharper*/
|
||||
|
||||
#ignore thumbnails created by windows
|
||||
Thumbs.db
|
||||
#Ignore files build by Visual Studio
|
||||
*.obj
|
||||
*.exe
|
||||
*.pdb
|
||||
*.user
|
||||
*.aps
|
||||
*.pch
|
||||
*.vspscc
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ncb
|
||||
*.suo
|
||||
*.tlb
|
||||
*.tlh
|
||||
*.bak
|
||||
*.cache
|
||||
*.log
|
||||
[Bb]in
|
||||
[Dd]ebug*/
|
||||
*.lib
|
||||
*.sbr
|
||||
obj/
|
||||
[Rr]elease*/
|
||||
_ReSharper*/
|
||||
[Tt]est[Rr]esult*
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -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