SmartThreadPool v2.0
This commit is contained in:
Ami Bar
2009-12-19 16:32:41 +02:00
parent b30b4abdda
commit 4d6ffb5851
89 changed files with 13714 additions and 2639 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

+316
View File
@@ -0,0 +1,316 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace STPCEDemo
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.MainMenu mainMenu1;
private UsageControl.UsageHistoryControl usageHistoryControl1;
private Button btnStartStop;
private Label label1;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (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.mainMenu1 = new System.Windows.Forms.MainMenu();
this.btnStartStop = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.lblThreadsInUse = new System.Windows.Forms.Label();
this.label7 = new System.Windows.Forms.Label();
this.lblThreadsInPool = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.spnMinThreads = new System.Windows.Forms.NumericUpDown();
this.label4 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.spnMaxThreads = new System.Windows.Forms.NumericUpDown();
this.spnIdleTimeout = new System.Windows.Forms.NumericUpDown();
this.spnWorkItemsPerSecond = new System.Windows.Forms.NumericUpDown();
this.label6 = new System.Windows.Forms.Label();
this.spnWorkItemDuration = new System.Windows.Forms.NumericUpDown();
this.label8 = new System.Windows.Forms.Label();
this.usageControl1 = new UsageControl.UsageControl();
this.usageHistoryControl1 = new UsageControl.UsageHistoryControl();
this.SuspendLayout();
//
// btnStartStop
//
this.btnStartStop.Location = new System.Drawing.Point(148, 10);
this.btnStartStop.Name = "btnStartStop";
this.btnStartStop.Size = new System.Drawing.Size(72, 20);
this.btnStartStop.TabIndex = 0;
this.btnStartStop.Text = "Start";
this.btnStartStop.Click += new System.EventHandler(this.btnStartStop_Click);
//
// label1
//
this.label1.Font = new System.Drawing.Font("Tahoma", 10F, System.Drawing.FontStyle.Bold);
this.label1.Location = new System.Drawing.Point(10, 10);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(143, 20);
this.label1.Text = "Smart Thread Pool";
//
// lblThreadsInUse
//
this.lblThreadsInUse.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular);
this.lblThreadsInUse.Location = new System.Drawing.Point(148, 106);
this.lblThreadsInUse.Name = "lblThreadsInUse";
this.lblThreadsInUse.Size = new System.Drawing.Size(72, 24);
this.lblThreadsInUse.Text = "0";
this.lblThreadsInUse.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// label7
//
this.label7.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular);
this.label7.Location = new System.Drawing.Point(10, 106);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(124, 24);
this.label7.Text = "Used threads (Green)";
//
// lblThreadsInPool
//
this.lblThreadsInPool.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular);
this.lblThreadsInPool.Location = new System.Drawing.Point(148, 88);
this.lblThreadsInPool.Name = "lblThreadsInPool";
this.lblThreadsInPool.Size = new System.Drawing.Size(72, 24);
this.lblThreadsInPool.Text = "0";
this.lblThreadsInPool.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// label2
//
this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular);
this.label2.Location = new System.Drawing.Point(10, 88);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(124, 24);
this.label2.Text = "Threads in pool (Red)";
//
// spnMinThreads
//
this.spnMinThreads.Location = new System.Drawing.Point(148, 125);
this.spnMinThreads.Maximum = new decimal(new int[] {
10,
0,
0,
0});
this.spnMinThreads.Name = "spnMinThreads";
this.spnMinThreads.Size = new System.Drawing.Size(72, 24);
this.spnMinThreads.TabIndex = 3;
this.spnMinThreads.ValueChanged += new System.EventHandler(this.spnMinThreads_ValueChanged);
//
// label4
//
this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular);
this.label4.Location = new System.Drawing.Point(10, 173);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(120, 24);
this.label4.Text = "Idle timeout (Seconds)";
//
// label3
//
this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular);
this.label3.Location = new System.Drawing.Point(10, 149);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(104, 24);
this.label3.Text = "Maximum Threads";
//
// label5
//
this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular);
this.label5.Location = new System.Drawing.Point(10, 125);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(104, 24);
this.label5.Text = "Minimum Threads";
//
// spnMaxThreads
//
this.spnMaxThreads.Location = new System.Drawing.Point(148, 149);
this.spnMaxThreads.Maximum = new decimal(new int[] {
10,
0,
0,
0});
this.spnMaxThreads.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this.spnMaxThreads.Name = "spnMaxThreads";
this.spnMaxThreads.Size = new System.Drawing.Size(72, 24);
this.spnMaxThreads.TabIndex = 4;
this.spnMaxThreads.Value = new decimal(new int[] {
5,
0,
0,
0});
this.spnMaxThreads.ValueChanged += new System.EventHandler(this.spnMaxThreads_ValueChanged);
//
// spnIdleTimeout
//
this.spnIdleTimeout.Location = new System.Drawing.Point(148, 173);
this.spnIdleTimeout.Maximum = new decimal(new int[] {
60,
0,
0,
0});
this.spnIdleTimeout.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this.spnIdleTimeout.Name = "spnIdleTimeout";
this.spnIdleTimeout.Size = new System.Drawing.Size(72, 24);
this.spnIdleTimeout.TabIndex = 5;
this.spnIdleTimeout.Value = new decimal(new int[] {
10,
0,
0,
0});
//
// spnWorkItemsPerSecond
//
this.spnWorkItemsPerSecond.Location = new System.Drawing.Point(148, 203);
this.spnWorkItemsPerSecond.Name = "spnWorkItemsPerSecond";
this.spnWorkItemsPerSecond.Size = new System.Drawing.Size(72, 24);
this.spnWorkItemsPerSecond.TabIndex = 6;
this.spnWorkItemsPerSecond.Value = new decimal(new int[] {
1,
0,
0,
0});
//
// label6
//
this.label6.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular);
this.label6.Location = new System.Drawing.Point(10, 203);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(120, 24);
this.label6.Text = "Work items/sec";
//
// spnWorkItemDuration
//
this.spnWorkItemDuration.Increment = new decimal(new int[] {
100,
0,
0,
0});
this.spnWorkItemDuration.Location = new System.Drawing.Point(148, 227);
this.spnWorkItemDuration.Maximum = new decimal(new int[] {
6000,
0,
0,
0});
this.spnWorkItemDuration.Name = "spnWorkItemDuration";
this.spnWorkItemDuration.Size = new System.Drawing.Size(72, 24);
this.spnWorkItemDuration.TabIndex = 7;
this.spnWorkItemDuration.Value = new decimal(new int[] {
100,
0,
0,
0});
//
// label8
//
this.label8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular);
this.label8.Location = new System.Drawing.Point(10, 227);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(132, 24);
this.label8.Text = "Work item duration (ms)";
//
// usageControl1
//
this.usageControl1.BackColor = System.Drawing.Color.Black;
this.usageControl1.Location = new System.Drawing.Point(10, 33);
this.usageControl1.Maximum = 10;
this.usageControl1.Name = "usageControl1";
this.usageControl1.Size = new System.Drawing.Size(41, 52);
this.usageControl1.TabIndex = 1;
this.usageControl1.Value1 = 0;
this.usageControl1.Value2 = 0;
//
// usageHistoryControl1
//
this.usageHistoryControl1.BackColor = System.Drawing.Color.Black;
this.usageHistoryControl1.Location = new System.Drawing.Point(66, 33);
this.usageHistoryControl1.Maximum = 10;
this.usageHistoryControl1.Name = "usageHistoryControl1";
this.usageHistoryControl1.Size = new System.Drawing.Size(154, 52);
this.usageHistoryControl1.TabIndex = 2;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.AutoScroll = true;
this.ClientSize = new System.Drawing.Size(240, 258);
this.Controls.Add(this.btnStartStop);
this.Controls.Add(this.spnWorkItemDuration);
this.Controls.Add(this.label8);
this.Controls.Add(this.spnWorkItemsPerSecond);
this.Controls.Add(this.label6);
this.Controls.Add(this.spnIdleTimeout);
this.Controls.Add(this.spnMaxThreads);
this.Controls.Add(this.label4);
this.Controls.Add(this.label3);
this.Controls.Add(this.label5);
this.Controls.Add(this.spnMinThreads);
this.Controls.Add(this.lblThreadsInUse);
this.Controls.Add(this.label7);
this.Controls.Add(this.lblThreadsInPool);
this.Controls.Add(this.label2);
this.Controls.Add(this.usageControl1);
this.Controls.Add(this.label1);
this.Controls.Add(this.usageHistoryControl1);
this.Menu = this.mainMenu1;
this.Name = "Form1";
this.Text = "Smart Thread Pool";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
}
#endregion
private UsageControl.UsageControl usageControl1;
private Label lblThreadsInUse;
private Label label7;
private Label lblThreadsInPool;
private Label label2;
private NumericUpDown spnMinThreads;
private Label label4;
private Label label3;
private Label label5;
private NumericUpDown spnMaxThreads;
private NumericUpDown spnIdleTimeout;
private NumericUpDown spnWorkItemsPerSecond;
private Label label6;
private NumericUpDown spnWorkItemDuration;
private Label label8;
}
}
+149
View File
@@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Amib.Threading;
using System.Threading;
namespace STPCEDemo
{
public partial class Form1 : Form
{
private bool running;
private readonly System.Windows.Forms.Timer uiTimer;
private SmartThreadPool _stp;
private readonly System.Windows.Forms.Timer wiTimer;
public Form1()
{
running = false;
InitializeComponent();
uiTimer = new System.Windows.Forms.Timer();
uiTimer.Interval = 1000;
uiTimer.Tick += new EventHandler(uiTimer_Tick);
wiTimer = new System.Windows.Forms.Timer();
wiTimer.Interval = 1000;
wiTimer.Tick += new EventHandler(wiTimer_Tick);
//Debug.WriteLine("Form Thread Priority is " + (int)GetCurrentThreadPriority());
}
private void Form1_Load(object sender, EventArgs e)
{
SetRunningState(false);
}
void uiTimer_Tick(object sender, EventArgs e)
{
if (null == _stp)
{
return;
}
try
{
int inUse = _stp.InUseThreads;
int inPool = _stp.ActiveThreads;
this.usageHistoryControl1.AddValues(inUse, inPool);
this.usageControl1.Value1 = inUse;
this.usageControl1.Value2 = inPool;
this.lblThreadsInUse.Text = inUse.ToString();
this.lblThreadsInPool.Text = inPool.ToString();
}
catch(Exception ex)
{
Debug.WriteLine(ex);
return;
}
}
void wiTimer_Tick(object sender, EventArgs e)
{
int count = Convert.ToInt32(spnWorkItemsPerSecond.Value);
int sleepDuration = Convert.ToInt32(spnWorkItemDuration.Value);
Debug.WriteLine(string.Format("{0}: C = {1}, S = {2}", DateTime.Now.ToString("HH:mm:ss"), count, sleepDuration));
for (int i = 0; i < count; i++)
{
_stp.QueueWorkItem(DoWork, sleepDuration);
}
}
private void DoWork(int sleepDuration)
{
//Debug.WriteLine("DoWork Thread Priority is " + (int)GetCurrentThreadPriority());
DateTime start = DateTime.Now;
//int sleepDuration = Convert.ToInt32(state);
Thread.Sleep(sleepDuration);
TimeSpan duration = DateTime.Now - start;
Debug.WriteLine(string.Format("{0}: Duration = {1}", DateTime.Now.ToString("HH:mm:ss"), duration.TotalMilliseconds));
//return null;
}
void btnStartStop_Click(object sender, EventArgs e)
{
SetRunningState(!running);
}
private void SetRunningState(bool newRunningState)
{
btnStartStop.Text = newRunningState ? "Stop" : "Start";
if (newRunningState)
{
_stp = new SmartThreadPool(
Convert.ToInt32(spnIdleTimeout.Value) * 1000,
Convert.ToInt32(spnMaxThreads.Value),
Convert.ToInt32(spnMinThreads.Value));
}
else
{
if (null != _stp)
{
_stp.Shutdown();
}
_stp = null;
}
spnIdleTimeout.Enabled = !newRunningState;
uiTimer.Enabled = newRunningState;
wiTimer.Enabled = newRunningState;
running = newRunningState;
}
private void spnMinThreads_ValueChanged(object sender, EventArgs e)
{
if (null != _stp)
{
_stp.MinThreads = Convert.ToInt32(spnMinThreads.Value);
}
}
private void spnMaxThreads_ValueChanged(object sender, EventArgs e)
{
if (null != _stp)
{
_stp.MaxThreads = Convert.ToInt32(spnMaxThreads.Value);
}
}
private static int GetCurrentThreadPriority()
{
IntPtr hThread = GetCurrentThread();
int priority = CeGetThreadPriority(hThread);
return priority;
}
[DllImport("coredll.dll", SetLastError = true)]
public static extern int CeGetThreadPriority(IntPtr hThread);
[DllImport("coredll.dll")]
public static extern IntPtr GetCurrentThread();
}
}
+129
View File
@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
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">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</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 for serialized 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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<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" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</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>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="mainMenu1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="$this.FormFactorShadowProperty" xml:space="preserve">
<value>WEBPAD</value>
</metadata>
<metadata name="$this.Skin" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
</root>
+44
View File
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
namespace STPCEDemo
{
public static class Pens
{
private static Pen _red = new Pen(Color.Red);
private static Pen _lawnGreen = new Pen(Color.LawnGreen);
private static Pen _green = new Pen(Color.Green);
private static Pen _darkGray = new Pen(Color.DarkGray);
private static Pen _white = new Pen(Color.White);
public static Pen Red
{
get { return _red; }
}
public static Pen LawnGreen
{
get { return _lawnGreen; }
}
public static Pen Green
{
get { return _green; }
}
public static Pen DarkGray
{
get { return _darkGray; }
}
public static Pen White
{
get { return _white; }
}
}
}
+18
View File
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace STPCEDemo
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[MTAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}
+33
View File
@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
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("STPCEDemo")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("STPCEDemo")]
[assembly: AssemblyCopyright("Copyright © 2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a9f7d57c-9b87-4b5e-81a5-9d4b2719b5b5")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
+60
View File
@@ -0,0 +1,60 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.1433
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace STPCEDemo.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("STPCEDemo.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
+117
View File
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
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">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</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 for serialized 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="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<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>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+115
View File
@@ -0,0 +1,115 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{356114BA-5F10-4DB6-9971-987CE11F765F}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>STPCEDemo</RootNamespace>
<AssemblyName>STPCEDemo</AssemblyName>
<ProjectTypeGuids>{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PlatformFamilyName>WindowsCE</PlatformFamilyName>
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
<OSVersion>5.0</OSVersion>
<DeployDirSuffix>STPCEDemo</DeployDirSuffix>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FormFactorID>
</FormFactorID>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;$(PlatformFamilyName)</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<FileAlignment>512</FileAlignment>
<WarningLevel>4</WarningLevel>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;$(PlatformFamilyName)</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<FileAlignment>512</FileAlignment>
<WarningLevel>4</WarningLevel>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Pens.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Form1.resx">
<SubType>Designer</SubType>
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="UsageControl.resx">
<DependentUpon>UsageControl.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="UsageHistoryControl.resx">
<DependentUpon>UsageHistoryControl.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="UsageControl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="UsageHistoryControl.cs">
<SubType>UserControl</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SmartThreadPool\SmartThreadPoolCE.csproj">
<Project>{D81DD596-C71F-4AC2-816C-63C19589E7E0}</Project>
<Name>SmartThreadPoolCE</Name>
</ProjectReference>
</ItemGroup>
<Import Condition="'$(TargetFrameworkVersion)' == 'v1.0'" Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.v1.targets" />
<Import Condition="'$(TargetFrameworkVersion)' == 'v2.0'" Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}">
<HostingProcess disable="1" />
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
+328
View File
@@ -0,0 +1,328 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Windows.Forms;
using STPCEDemo;
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,
this.ClientRectangle.Left, this.ClientRectangle.Top,
this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Top);
g.DrawLine(Pens.DarkGray,
this.ClientRectangle.Left, this.ClientRectangle.Top,
this.ClientRectangle.Left, this.ClientRectangle.Height - PenWidth);
g.DrawLine(Pens.White,
this.ClientRectangle.Left, this.ClientRectangle.Height - PenWidth,
this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Height - PenWidth);
g.DrawLine(Pens.White,
this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Top,
this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Height - PenWidth);
}
}
}
+130
View File
@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used forserialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.TrayHeight" type="System.Int32, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>80</value>
</data>
<data name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>(Default)</value>
</data>
<data name="$this.Localizable" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.Name">
<value>UsageControl</value>
</data>
<data name="$this.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="$this.GridSize" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>8, 8</value>
</data>
</root>
+192
View File
@@ -0,0 +1,192 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using STPCEDemo;
namespace UsageControl
{
/// <summary>
/// Summary description for UsageHistoryControl.
/// </summary>
public class UsageHistoryControl : System.Windows.Forms.UserControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private const int squareWidth = 12;
private const int maxLastValuesCount = 2000;
private const int shiftStep = 3;
private int shift = 0;
private int [] lastValues1 = new int[maxLastValuesCount];
private int [] lastValues2 = new int[maxLastValuesCount];
private int nextValueIndex;
private int lastValuesCount;
private int max = 100;
private int min = 0;
public UsageHistoryControl()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
EnableDoubleBuffering();
Reset();
}
public void Reset()
{
lastValues1.Initialize();
lastValues2.Initialize();
nextValueIndex = 0;
lastValuesCount = 0;
Invalidate();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// UsageHistoryControl
//
this.BackColor = System.Drawing.Color.Black;
this.Name = "UsageHistoryControl";
}
#endregion
private void EnableDoubleBuffering()
{
// Set the value of the double-buffering style bits to true.
//this.SetStyle(ControlStyles.DoubleBuffer |
// ControlStyles.UserPaint |
// ControlStyles.AllPaintingInWmPaint,
// true);
//this.UpdateStyles();
}
protected override void OnResize(EventArgs e)
{
// Invalidate the control to get a repaint.
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
for(int i = 0; i <= ClientRectangle.Width+squareWidth; i += squareWidth)
{
g.DrawLine(Pens.Green, i-shift, 0, i-shift, ClientRectangle.Height);
}
for(int i = 0; i < ClientRectangle.Height; i += squareWidth)
{
g.DrawLine(Pens.Green, 0, i, ClientRectangle.Width, i);
}
int startValueIndex = (nextValueIndex-1+maxLastValuesCount)%maxLastValuesCount;
int prevVal1 = GetRelativeValue(lastValues1[startValueIndex]);
int prevVal2 = GetRelativeValue(lastValues2[startValueIndex]);
for(int i = 1; i < lastValuesCount; ++i)
{
int index = nextValueIndex - 1 - i;
if (index < 0)
{
index += maxLastValuesCount;
}
int val1 = GetRelativeValue(lastValues1[index]);
int val2 = GetRelativeValue(lastValues2[index]);
g.DrawLine(
Pens.Red,
ClientRectangle.Width-(i-1)*shiftStep, ClientRectangle.Height-prevVal2,
ClientRectangle.Width-i*shiftStep, ClientRectangle.Height-val2);
g.DrawLine(
Pens.LawnGreen,
ClientRectangle.Width-(i-1)*shiftStep, ClientRectangle.Height-prevVal1,
ClientRectangle.Width-i*shiftStep, ClientRectangle.Height-val1);
prevVal1 = val1;
prevVal2 = val2;
}
}
private int GetRelativeValue(int val)
{
int result = val * (ClientRectangle.Height-2) / max + 1;
return result;
}
public void AddValues(int val1, int val2)
{
lastValues1[nextValueIndex] = val1;
lastValues2[nextValueIndex] = val2;
nextValueIndex++;
nextValueIndex %= maxLastValuesCount;
lastValuesCount++;
if (lastValuesCount > maxLastValuesCount)
{
lastValuesCount = maxLastValuesCount;
}
shift += shiftStep;
shift %= squareWidth;
Invalidate();
}
public int Maximum
{
get
{
return max;
}
set
{
// Make sure that the maximum value is never set lower than the minimum value.
if (value < min)
{
min = value;
}
max = value;
// Invalidate the control to get a repaint.
this.Invalidate();
}
}
}
}
+130
View File
@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used forserialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.Name">
<value>UsageHistoryControl</value>
</data>
<data name="$this.TrayHeight" type="System.Int32, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>80</value>
</data>
<data name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>(Default)</value>
</data>
<data name="$this.Localizable" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
<data name="$this.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="$this.GridSize" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>8, 8</value>
</data>
</root>
+21 -34
View File
@@ -6,42 +6,29 @@ namespace Examples
{
public class CatchExceptionExample
{
private class DivArgs
{
public int x;
public int y;
}
public void DoWork()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
public void DoWork()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemResult<double> wir = smartThreadPool.QueueWorkItem(new Func<double, double, double>(DoDiv), 10.0, 0.0);
DivArgs divArgs = new DivArgs();
divArgs.x = 10;
divArgs.y = 0;
try
{
double result = wir.Result;
}
// Catch the exception that Result threw
catch (WorkItemResultException e)
{
// Dump the inner exception which DoDiv threw
Debug.WriteLine(e.InnerException);
}
IWorkItemResult wir =
smartThreadPool.QueueWorkItem(new
WorkItemCallback(this.DoDiv), divArgs);
smartThreadPool.Shutdown();
}
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);
}
}
private double DoDiv(double x, double y)
{
return x / y;
}
}
}
+45
View File
@@ -0,0 +1,45 @@
using System.Threading;
using Amib.Threading;
namespace Examples
{
public class CooperativeCancelExample
{
public void DoWork(object state)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
// Queue the work item
IWorkItemResult wir = smartThreadPool.QueueWorkItem(DoRealWork);
// Give the work item some time to complete.
Thread.Sleep(1000);
// If the work item hasn't completed yet then cancel it.
if (!wir.IsCompleted)
{
wir.Cancel();
}
smartThreadPool.Shutdown();
}
// Do some lengthy work
private void DoRealWork()
{
// Do something here.
// Sample SmartThreadPool.IsWorkItemCanceled
if (SmartThreadPool.IsWorkItemCanceled)
{
return;
}
// Sample the SmartThreadPool.IsWorkItemCanceled in a loop
while (!SmartThreadPool.IsWorkItemCanceled)
{
// Do some real work here
}
}
}
}
+108
View File
@@ -0,0 +1,108 @@
using Amib.Threading;
namespace STPExamples
{
/// <summary>
/// This is a Parallel QuickSort example.
/// It shows how to use the QueueWorkItem with Action<T> methods.
/// </summary>
public class ParallelQuickSort
{
public static void Main()
{
// Generate an array
int[] array = GenerateArray(100);
// Create a Smart Thread Pool
SmartThreadPool stp = new SmartThreadPool();
// Use the Smart Thread Pool to parallel the sort
QuickSort(stp, array);
}
/// <summary>
/// QuickSort array using wig to parallel the sort
/// </summary>
/// <param name="wig">A IWorkItemsGroup to use to parallel the sort</param>
/// <param name="array">The array of items to sort</param>
public static void QuickSort(IWorkItemsGroup wig, int[] array)
{
// Initiate the QuickSort
wig.QueueWorkItem(QuickSort, wig, array, 0, array.Length - 1);
// Wait for the sort to complete.
wig.WaitForIdle();
}
/// <summary>
/// Sort a subarray in array, starting with the left item and ending in the right item.
/// The method uses the IWorkItemsGroup wig to parallel the sort.
/// </summary>
/// <param name="wig">A IWorkItemsGroup to use to parallel the sort</param>
/// <param name="array">The array of items to sort</param>
/// <param name="left">The left index in the subarray</param>
/// <param name="right">The right index in the subarray</param>
private static void QuickSort(IWorkItemsGroup wig, int[] array, int left, int right)
{
if (right > left)
{
int pivotIndex = left;
int pivotNewIndex = Partition(array, left, right, pivotIndex);
wig.QueueWorkItem(QuickSort, wig, array, left, pivotNewIndex - 1);
wig.QueueWorkItem(QuickSort, wig, array, pivotNewIndex + 1, right);
}
}
/// <summary>
/// Partition a subarray of array
/// (This is part of the QuickSort algorithm)
/// </summary>
/// <returns></returns>
private static int Partition(int[] array, int left, int right, int pivotIndex)
{
int pivotValue = array[pivotIndex];
Swap(array, pivotIndex, right);
int storeIndex = left;
for (int i = left; i < right; i++)
{
if (array[i] <= pivotValue)
{
Swap(array, i, storeIndex);
++storeIndex;
}
}
Swap(array, storeIndex, right);
return storeIndex;
}
/// <summary>
/// Swap between two item in the array
/// </summary>
/// <param name="array">Array of integers</param>
/// <param name="index1">First index</param>
/// <param name="index2">Second index</param>
private static void Swap(int[] array, int index1, int index2)
{
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
/// <summary>
/// Generate an array with the numbers 0-count ordered in reverse
/// </summary>
/// <param name="count">The number of items in the array</param>
/// <returns>Returns the generated array</returns>
private static int[] GenerateArray(int count)
{
int[] array = new int[count];
for (int i = 0; i < array.Length; i++)
{
array[i] = array.Length - i;
}
return array;
}
}
}
+19 -3
View File
@@ -16,11 +16,10 @@
<DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
<DefaultTargetSchema>IE50</DefaultTargetSchema>
<DelaySign>false</DelaySign>
<OutputType>Library</OutputType>
<OutputType>Exe</OutputType>
<RootNamespace>STPExamples</RootNamespace>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<StartupObject>
</StartupObject>
<StartupObject>STPExamples.ParallelQuickSort</StartupObject>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
@@ -72,6 +71,16 @@
<DebugType>none</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseCE|AnyCPU' ">
<OutputPath>bin\ReleaseCE\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<BaseAddress>285212672</BaseAddress>
<Optimize>true</Optimize>
<DebugType>
</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System">
<Name>System</Name>
@@ -79,6 +88,10 @@
<Reference Include="System.Data">
<Name>System.Data</Name>
</Reference>
<Reference Include="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\Program Files\Microsoft Visual Studio 8\SmartDevices\SDK\CompactFramework\2.0\v2.0\WindowsCE\System.Drawing.dll</HintPath>
</Reference>
<Reference Include="System.Xml">
<Name>System.XML</Name>
</Reference>
@@ -96,12 +109,14 @@
<Compile Include="CatchExceptionExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="CooperativeCancelExample.cs" />
<Compile Include="GetExceptionExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="OnWIGIdleEventExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ParallelQuickSort.cs" />
<Compile Include="PriorityExample.cs">
<SubType>Code</SubType>
</Compile>
@@ -114,6 +129,7 @@
<Compile Include="SuspendedWIGStartExample.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ThreadEventsExample.cs" />
<Compile Include="WaitForAllExample.cs">
<SubType>Code</SubType>
</Compile>
+20 -21
View File
@@ -1,35 +1,34 @@
using System;
using Amib.Threading;
namespace Examples
{
public class SimpleExample
{
public void DoWork(object state)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
public void DoWork(int[] numbers)
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
// Queue the work item
IWorkItemResult wir =
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoRealWork),
state);
// Queue the work item
IWorkItemResult<double> wir = smartThreadPool.QueueWorkItem(new Func<int[], double>(CalcAverage), numbers);
// Do some other work here
// Do some other work here
// Get the result of the operation
object result = wir.Result;
// Get the result of the operation
double average = wir.Result;
smartThreadPool.Shutdown();
}
smartThreadPool.Shutdown();
}
// Do the real work
private object DoRealWork(object state)
{
object result = null;
// Do the real work
private double CalcAverage(int[] numbers)
{
double average = 0.0;
// Do the real work here and put the result in 'result'
// Do the real work here and put
// the result in 'result'
return result;
}
}
return average;
}
}
}
+58
View File
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Text;
using Amib.Threading;
namespace STPExamples
{
public class MyResource : IDisposable
{
// ...
public void DoIt()
{
//...
}
public void Dispose()
{
//...
}
}
public class ThreadEventsExample
{
public static void Main()
{
SmartThreadPool stp = new SmartThreadPool();
stp.OnThreadInitialization += new ThreadInitializationHandler(OnInitialization);
stp.OnThreadTermination += new ThreadTerminationHandler(OnTermination);
stp.QueueWorkItem(DoSomeWork);
}
[ThreadStatic]
private static MyResource _resource;
public static void OnInitialization()
{
// Initialize the resource
_resource = new MyResource();
}
private static object DoSomeWork(object state)
{
// Use the resouce
_resource.DoIt();
return null;
}
public static void OnTermination()
{
// Do resource cleanup
_resource.Dispose();
}
}
}
+693
View File
@@ -0,0 +1,693 @@
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
using System.Reflection;
#pragma warning disable 168
namespace SmartThreadPoolTests
{
public static class QueueWorkItemHelper
{
//IWorkItemResult QueueWorkItem(WorkItemCallback callback);
public static void TestQueueWorkItemCall(IWorkItemsGroup wig)
{
WorkItemInfo wii = new WorkItemInfo();
WorkItemInfoComparer wiic = new WorkItemInfoComparer(wii);
IWorkItemResult wir = wig.QueueWorkItem(wiic.CompareWorkItemInfo);
bool success = (bool)wir.Result;
Assert.IsTrue(success);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
public static void TestQueueWorkItemCallPrio(IWorkItemsGroup wig)
{
WorkItemInfo wii = new WorkItemInfo();
wii.WorkItemPriority = WorkItemPriority.AboveNormal;
WorkItemInfoComparer wiic = new WorkItemInfoComparer(wii);
IWorkItemResult wir = wig.QueueWorkItem((WorkItemCallback)wiic.CompareWorkItemInfo, WorkItemPriority.AboveNormal);
bool success = (bool)wir.Result;
Assert.IsTrue(success);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
public static void TestQueueWorkItemCallStat(IWorkItemsGroup wig)
{
object state = new object();
WorkItemInfo wii = new WorkItemInfo();
WorkItemInfoComparer wiic = new WorkItemInfoComparer(wii, state);
IWorkItemResult wir = wig.QueueWorkItem((WorkItemCallback) wiic.CompareWorkItemInfo, state);
bool success = (bool)wir.Result;
Assert.IsTrue(success);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
public static void TestQueueWorkItemCallStatPrio(IWorkItemsGroup wig)
{
object state = new object();
WorkItemInfo wii = new WorkItemInfo();
wii.WorkItemPriority = WorkItemPriority.AboveNormal;
WorkItemInfoComparer wiic = new WorkItemInfoComparer(wii, state);
IWorkItemResult wir = wig.QueueWorkItem(wiic.CompareWorkItemInfo, state, WorkItemPriority.AboveNormal);
bool success = (bool)wir.Result;
Assert.IsTrue(success);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
public static void TestQueueWorkItemCallStatPost(IWorkItemsGroup wig)
{
bool postExecuteCalled = false;
object state = new object();
PostExecuteWorkItemCallback postExecuteWorkItemCallback = delegate(IWorkItemResult w) { postExecuteCalled = true; };
WorkItemInfo wii = new WorkItemInfo();
wii.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
WorkItemInfoComparer wiic = new WorkItemInfoComparer(wii, state);
IWorkItemResult wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
bool success = (bool)wir.Result;
Assert.IsTrue(success);
Assert.IsTrue(postExecuteCalled);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
public static void TestQueueWorkItemCallStatPostPrio(IWorkItemsGroup wig)
{
bool postExecuteCalled = false;
object state = new object();
PostExecuteWorkItemCallback postExecuteWorkItemCallback = delegate(IWorkItemResult w) { postExecuteCalled = true; };
WorkItemInfo wii = new WorkItemInfo();
wii.WorkItemPriority = WorkItemPriority.BelowNormal;
wii.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
WorkItemInfoComparer wiic = new WorkItemInfoComparer(wii, state);
IWorkItemResult wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
WorkItemPriority.BelowNormal);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
bool success = (bool)wir.Result;
Assert.IsTrue(success);
Assert.IsTrue(postExecuteCalled);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
public static void TestQueueWorkItemCallStatPostPflg(IWorkItemsGroup wig)
{
bool postExecuteCalled;
CallToPostExecute callToPostExecute;
object state = new object();
PostExecuteWorkItemCallback postExecuteWorkItemCallback = delegate(IWorkItemResult w) { postExecuteCalled = true; };
WorkItemInfo wii = new WorkItemInfo();
wii.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
WorkItemInfoComparer wiic = new WorkItemInfoComparer(wii, state);
IWorkItemResult wir;
bool success;
/////////////////////////////////////////////////////////////////////////////
callToPostExecute = CallToPostExecute.Always;
// Check without cancel
postExecuteCalled = false;
wiic.SleepTime = 0;
wii.CallToPostExecute = callToPostExecute;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
success = (bool)wir.Result;
Assert.IsTrue(success);
Assert.IsTrue(postExecuteCalled);
// Check with cancel
success = false;
postExecuteCalled = false;
wiic.SleepTime = 100;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute);
wir.Cancel();
// We must wait for idle to let the post execute run
wig.WaitForIdle();
Assert.IsTrue(postExecuteCalled);
try
{
wir.GetResult();
}
catch (WorkItemCancelException ce)
{
success = true;
}
Assert.IsTrue(success);
/////////////////////////////////////////////////////////////////////////////
callToPostExecute = CallToPostExecute.Never;
postExecuteCalled = false;
wiic.SleepTime = 0;
wii.CallToPostExecute = callToPostExecute;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
success = (bool)wir.Result;
Assert.IsTrue(success);
Assert.IsFalse(postExecuteCalled);
// Check with cancel
success = false;
postExecuteCalled = false;
wiic.SleepTime = 100;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute);
wir.Cancel();
// We must wait for idle to let the post execute run
wig.WaitForIdle();
Assert.IsFalse(postExecuteCalled);
try
{
wir.GetResult();
}
catch (WorkItemCancelException ce)
{
success = true;
}
Assert.IsTrue(success);
/////////////////////////////////////////////////////////////////////////////
callToPostExecute = CallToPostExecute.WhenWorkItemNotCanceled;
postExecuteCalled = false;
wiic.SleepTime = 0;
wii.CallToPostExecute = callToPostExecute;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
success = (bool)wir.Result;
Assert.IsTrue(success);
Assert.IsTrue(postExecuteCalled);
// Check with cancel
success = false;
postExecuteCalled = false;
wiic.SleepTime = 100;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute);
wir.Cancel();
// We must wait for idle to let the post execute run
wig.WaitForIdle();
Assert.IsFalse(postExecuteCalled);
try
{
wir.GetResult();
}
catch (WorkItemCancelException ce)
{
success = true;
}
Assert.IsTrue(success);
/////////////////////////////////////////////////////////////////////////////
callToPostExecute = CallToPostExecute.WhenWorkItemCanceled;
postExecuteCalled = false;
wiic.SleepTime = 0;
wii.CallToPostExecute = callToPostExecute;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
success = (bool)wir.Result;
Assert.IsTrue(success);
Assert.IsFalse(postExecuteCalled);
// Check with cancel
success = false;
postExecuteCalled = false;
wiic.SleepTime = 100;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute);
wir.Cancel();
// We must wait for idle to let the post execute run
wig.WaitForIdle();
Assert.IsTrue(postExecuteCalled);
try
{
wir.GetResult();
}
catch (WorkItemCancelException ce)
{
success = true;
}
Assert.IsTrue(success);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
public static void TestQueueWorkItemCallStatPostPflgPrio(IWorkItemsGroup wig)
{
bool postExecuteCalled;
CallToPostExecute callToPostExecute;
object state = new object();
PostExecuteWorkItemCallback postExecuteWorkItemCallback = delegate(IWorkItemResult w) { postExecuteCalled = true; };
WorkItemInfo wii = new WorkItemInfo();
wii.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
WorkItemInfoComparer wiic = new WorkItemInfoComparer(wii, state);
WorkItemPriority workItemPriority;
IWorkItemResult wir;
bool success;
/////////////////////////////////////////////////////////////////////////////
callToPostExecute = CallToPostExecute.Always;
workItemPriority = WorkItemPriority.Lowest;
// Check without cancel
postExecuteCalled = false;
wiic.SleepTime = 0;
wii.CallToPostExecute = callToPostExecute;
wii.WorkItemPriority = workItemPriority;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute,
workItemPriority);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
success = (bool)wir.Result;
Assert.IsTrue(success);
Assert.IsTrue(postExecuteCalled);
// Check with cancel
success = false;
postExecuteCalled = false;
wiic.SleepTime = 100;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute,
workItemPriority);
wir.Cancel();
// We must wait for idle to let the post execute run
wig.WaitForIdle();
Assert.IsTrue(postExecuteCalled);
try
{
wir.GetResult();
}
catch (WorkItemCancelException ce)
{
success = true;
}
Assert.IsTrue(success);
/////////////////////////////////////////////////////////////////////////////
callToPostExecute = CallToPostExecute.Never;
workItemPriority = WorkItemPriority.Highest;
postExecuteCalled = false;
wiic.SleepTime = 0;
wii.CallToPostExecute = callToPostExecute;
wii.WorkItemPriority = workItemPriority;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute,
workItemPriority);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
success = (bool)wir.Result;
Assert.IsTrue(success);
Assert.IsFalse(postExecuteCalled);
// Check with cancel
success = false;
postExecuteCalled = false;
wiic.SleepTime = 100;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute,
workItemPriority);
wir.Cancel();
// We must wait for idle to let the post execute run
wig.WaitForIdle();
Assert.IsFalse(postExecuteCalled);
try
{
wir.GetResult();
}
catch (WorkItemCancelException ce)
{
success = true;
}
Assert.IsTrue(success);
/////////////////////////////////////////////////////////////////////////////
callToPostExecute = CallToPostExecute.WhenWorkItemNotCanceled;
workItemPriority = WorkItemPriority.AboveNormal;
postExecuteCalled = false;
wiic.SleepTime = 0;
wii.CallToPostExecute = callToPostExecute;
wii.WorkItemPriority = workItemPriority;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute,
workItemPriority);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
success = (bool)wir.Result;
Assert.IsTrue(success);
Assert.IsTrue(postExecuteCalled);
// Check with cancel
success = false;
postExecuteCalled = false;
wiic.SleepTime = 100;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute,
workItemPriority);
wir.Cancel();
// We must wait for idle to let the post execute run
wig.WaitForIdle();
Assert.IsFalse(postExecuteCalled);
try
{
wir.GetResult();
}
catch (WorkItemCancelException ce)
{
success = true;
}
Assert.IsTrue(success);
/////////////////////////////////////////////////////////////////////////////
callToPostExecute = CallToPostExecute.WhenWorkItemCanceled;
workItemPriority = WorkItemPriority.BelowNormal;
postExecuteCalled = false;
wiic.SleepTime = 0;
wii.CallToPostExecute = callToPostExecute;
wii.WorkItemPriority = workItemPriority;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute,
workItemPriority);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
success = (bool)wir.Result;
Assert.IsTrue(success);
Assert.IsFalse(postExecuteCalled);
// Check with cancel
success = false;
postExecuteCalled = false;
wiic.SleepTime = 100;
wir = wig.QueueWorkItem(
wiic.CompareWorkItemInfo,
state,
postExecuteWorkItemCallback,
callToPostExecute,
workItemPriority);
wir.Cancel();
// We must wait for idle to let the post execute run
wig.WaitForIdle();
Assert.IsTrue(postExecuteCalled);
try
{
wir.GetResult();
}
catch (WorkItemCancelException ce)
{
success = true;
}
Assert.IsTrue(success);
}
//IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
public static void TestQueueWorkItemInfoCall(IWorkItemsGroup wig)
{
WorkItemInfo wii = new WorkItemInfo();
wii.CallToPostExecute = CallToPostExecute.Never;
wii.DisposeOfStateObjects = true;
wii.PostExecuteWorkItemCallback = delegate(IWorkItemResult w) { };
wii.UseCallerCallContext = true;
wii.UseCallerHttpContext = true;
wii.WorkItemPriority = WorkItemPriority.Highest;
WorkItemInfoComparer wiic = new WorkItemInfoComparer(wii);
IWorkItemResult wir = wig.QueueWorkItem(wii, wiic.CompareWorkItemInfo);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
bool success = (bool)wir.Result;
Assert.IsTrue(success);
}
//IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
public static void TestQueueWorkItemInfoCallStat(IWorkItemsGroup wig)
{
object state = new object();
WorkItemInfo wii = new WorkItemInfo();
wii.CallToPostExecute = CallToPostExecute.Never;
wii.DisposeOfStateObjects = true;
wii.PostExecuteWorkItemCallback = delegate(IWorkItemResult w) { };
wii.UseCallerCallContext = true;
wii.UseCallerHttpContext = true;
wii.WorkItemPriority = WorkItemPriority.Highest;
WorkItemInfoComparer wiic = new WorkItemInfoComparer(wii, state);
IWorkItemResult wir = wig.QueueWorkItem(wii, wiic.CompareWorkItemInfo, state);
// We must wait for idle to let the post execute run
wig.WaitForIdle();
bool success = (bool)wir.Result;
Assert.IsTrue(success);
}
private static WorkItemInfo GetCurrentWorkItemInfo()
{
object threadEntry = typeof(SmartThreadPool).GetField("_threadEntry", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
object workitem = threadEntry.GetType().GetField("_currentWorkItem", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(threadEntry);
WorkItemInfo wii = (WorkItemInfo)workitem.GetType().GetField("_workItemInfo", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(workitem);
return wii;
}
private class WorkItemInfoComparer
{
private WorkItemInfo _neededWorkItemInfo;
private object _state;
private int _sleepTime = 0;
public int SleepTime
{
get { return _sleepTime; }
set { _sleepTime = value; }
}
public WorkItemInfoComparer(WorkItemInfo workItemInfo)
{
_neededWorkItemInfo = workItemInfo;
_state = null;
}
public WorkItemInfoComparer(WorkItemInfo workItemInfo, object state)
{
_neededWorkItemInfo = workItemInfo;
_state = state;
}
public object CompareWorkItemInfo(object state)
{
bool equals = object.Equals(_state, state);
if (equals)
{
WorkItemInfo currentWorkItemInfo = GetCurrentWorkItemInfo();
equals = CompareWorkItemInfo(currentWorkItemInfo, _neededWorkItemInfo);
}
if (_sleepTime > 0)
{
Thread.Sleep(_sleepTime);
}
return equals;
}
private bool CompareWorkItemInfo(WorkItemInfo wii1, WorkItemInfo wii2)
{
bool equal = true;
equal = equal && (wii1.CallToPostExecute == wii2.CallToPostExecute);
equal = equal && (wii1.DisposeOfStateObjects == wii2.DisposeOfStateObjects);
equal = equal && (wii1.PostExecuteWorkItemCallback == wii2.PostExecuteWorkItemCallback);
equal = equal && (wii1.UseCallerCallContext == wii2.UseCallerCallContext);
equal = equal && (wii1.UseCallerHttpContext == wii2.UseCallerHttpContext);
equal = equal && (wii1.WorkItemPriority == wii2.WorkItemPriority);
return equal;
}
}
}
}
+27 -3
View File
@@ -60,7 +60,7 @@
<DefineConstants>TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>false</DebugSymbols>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
@@ -70,11 +70,21 @@
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>none</DebugType>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseCE|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ReleaseCE\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<BaseAddress>285212672</BaseAddress>
<Optimize>true</Optimize>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework, Version=2.2.5.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
<Reference Include="nunit.framework, Version=2.2.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
<Reference Include="System">
<Name>System</Name>
</Reference>
@@ -94,12 +104,26 @@
<Compile Include="AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestFalseFillStateWithParams.cs" />
<Compile Include="TestFillStateWithParams.cs" />
<Compile Include="TestWIGFillStateWithParams.cs" />
<Compile Include="TestWIGActionT.cs" />
<Compile Include="TestWIGFuncT.cs" />
<Compile Include="TestActionT.cs" />
<Compile Include="TestFuncT.cs" />
<Compile Include="TestWIGQueueWorkItem.cs" />
<Compile Include="QueueWorkItemHelper.cs" />
<Compile Include="TestQueueWorkItem.cs" />
<Compile Include="TestCancel.cs" />
<Compile Include="TestConcurrencyChanges.cs" />
<Compile Include="PermutationGenerator.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestChainedDelegates.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TestThreadsCreate.cs" />
<Compile Include="TestWIGConcurrencyChanges.cs" />
<Compile Include="TestExceptions.cs">
<SubType>Code</SubType>
</Compile>
+124
View File
@@ -0,0 +1,124 @@
using Amib.Threading;
using NUnit.Framework;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for TestCancel.
/// </summary>
[TestFixture]
[Category("TestActionT")]
public class TestActionT
{
private SmartThreadPool _stp;
private object _result;
[SetUp]
public void Init()
{
_stp = new SmartThreadPool();
}
[TearDown]
public void Fini()
{
_stp.Shutdown();
}
[Test]
public void ActionT0()
{
_result = null;
IWorkItemResult wir = _stp.QueueWorkItem(MaxInt);
wir.GetResult();
Assert.AreEqual(_result, int.MaxValue);
}
[Test]
public void ActionT1()
{
_result = null;
IWorkItemResult wir = _stp.QueueWorkItem(Not, true);
wir.GetResult();
Assert.AreEqual(_result, false);
}
[Test]
public void ActionT2()
{
_result = null;
IWorkItemResult wir = _stp.QueueWorkItem(Concat, "ABC", "xyz");
wir.GetResult();
Assert.AreEqual(_result, "ABCxyz");
}
[Test]
public void ActionT3()
{
_result = null;
IWorkItemResult wir = _stp.QueueWorkItem(Substring, "ABCDEF", 1, 2);
wir.GetResult();
Assert.AreEqual(_result, "BC");
}
[Test]
public void ActionT4()
{
_result = null;
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IWorkItemResult wir = _stp.QueueWorkItem(Subarray, numbers, 1, 2, 3);
wir.GetResult();
Assert.AreEqual(_result, new int[] { 2, 3, 2, 3, 2, 3, });
}
private void MaxInt()
{
_result = int.MaxValue;
}
private void Not(bool flag)
{
_result = !flag;
}
private void Concat(string s1, string s2)
{
_result = s1 + s2;
}
private void Substring(string s, int startIndex, int length)
{
_result = s.Substring(startIndex, length);
}
private void Subarray(int[] numbers, int startIndex, int length, int repeat)
{
int[] result = new int[length * repeat];
for (int i = 0; i < repeat; i++)
{
for (int j = 0; j < length; j++)
{
result[i * length + j] = numbers[startIndex + j];
}
}
_result = result;
}
}
}
+806
View File
@@ -0,0 +1,806 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for TestCancel.
/// </summary>
[TestFixture]
[Category("TestCancel")]
public class TestCancel
{
/// <summary>
/// 1. Create STP in suspended mode
/// 2. Queue work item into the STP
/// 3. Cancel the work item
/// 4. Work item's GetResult should throw WorkItemCancelException
/// </summary>
[Test]
[ExpectedException(typeof(WorkItemCancelException))]
public void CancelInQueueWorkItem()
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.StartSuspended = true;
SmartThreadPool stp = new SmartThreadPool(stpStartInfo);
IWorkItemResult wir = stp.QueueWorkItem(delegate(object state) { return null; });
wir.Cancel();
Assert.IsTrue(wir.IsCanceled);
try
{
wir.GetResult();
}
finally
{
stp.Shutdown();
}
}
/// <summary>
/// 1. Create STP
/// 2. Queue work item that takes some time
/// 3. Wait for it to start
/// 4. Cancel the work item (soft)
/// 5. Work item's GetResult should throw WorkItemCancelException
/// </summary>
[Test]
[ExpectedException(typeof(WorkItemCancelException))]
public void CancelInProgressWorkItemSoft()
{
ManualResetEvent waitToStart = new ManualResetEvent(false);
SmartThreadPool stp = new SmartThreadPool();
IWorkItemResult wir = stp.QueueWorkItem(
delegate(object state) { waitToStart.Set(); Thread.Sleep(100); return null; }
);
waitToStart.WaitOne();
wir.Cancel(false);
Assert.IsTrue(wir.IsCanceled);
try
{
wir.GetResult();
}
finally
{
stp.Shutdown();
}
}
/// <summary>
/// 1. Create STP
/// 2. Queue work item that:
/// a. Sleep for 0.1 seconds
/// b. Increment the counter
/// 3. Wait for the work item to start
/// 4. Cancel the work item (abort)
/// 5. Make sure the work item result indicates the work item has been cancelled.
/// 6. Make sure the counter incrementation didn't happen
/// 7. Work item's GetResult should throw WorkItemCancelException
/// </summary>
[Test]
[ExpectedException(typeof(WorkItemCancelException))]
public void CancelInProgressWorkItemAbort()
{
ManualResetEvent waitToStart = new ManualResetEvent(false);
int counter = 0;
SmartThreadPool stp = new SmartThreadPool();
IWorkItemResult wir = stp.QueueWorkItem(
delegate(object state) { waitToStart.Set() ; Thread.Sleep(100); ++counter; return null; }
);
waitToStart.WaitOne();
wir.Cancel(true);
Assert.IsTrue(wir.IsCanceled);
Assert.AreEqual(counter, 0);
try
{
wir.GetResult();
}
finally
{
stp.Shutdown();
}
}
/// <summary>
/// 1. Create STP
/// 2. Queue work item that takes some time
/// 3. Wait for it to start
/// 4. Cancel the work item (soft)
/// 5. Make sure, in the work item, that SmartThreadPool.IsWorkItemCanceled is true
/// 5. Wait for the STP to get idle
/// 6. Work item's GetResult should throw WorkItemCancelException
/// </summary>
[Test]
public void CancelInProgressWorkItemSoftWithSample()
{
bool cancelled = false;
ManualResetEvent waitToStart = new ManualResetEvent(false);
ManualResetEvent waitToComplete = new ManualResetEvent(false);
SmartThreadPool stp = new SmartThreadPool();
IWorkItemResult wir = stp.QueueWorkItem(
delegate(object state) {
waitToStart.Set();
Thread.Sleep(100);
cancelled = SmartThreadPool.IsWorkItemCanceled;
waitToComplete.Set();
return null;
}
);
waitToStart.WaitOne();
wir.Cancel(false);
waitToComplete.WaitOne();
Assert.IsTrue(cancelled);
stp.Shutdown();
}
/// <summary>
/// 1. Create STP in suspended mode
/// 2. Queue work item into the STP
/// 3. Cancel the work item
/// 4. Start the STP
/// 5. Wait for the STP to get idle
/// 6. Work item's GetResult should throw WorkItemCancelException
/// 7. Cancel the work item again
/// 8. Work item's GetResult should throw WorkItemCancelException
/// </summary>
[Test]
[ExpectedException(typeof(WorkItemCancelException))]
public void CancelCanceledWorkItem()
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.StartSuspended = true;
SmartThreadPool stp = new SmartThreadPool(stpStartInfo);
IWorkItemResult wir = stp.QueueWorkItem(delegate(object state) { return null; });
int counter = 0;
wir.Cancel();
try
{
wir.GetResult();
}
catch (WorkItemCancelException ce)
{
ce.GetHashCode();
++counter;
}
Assert.AreEqual(counter, 1);
wir.Cancel();
try
{
wir.GetResult();
}
finally
{
stp.Shutdown();
}
}
/// <summary>
/// 1. Create STP
/// 2. Queue work item into the STP
/// 3. Wait for the STP to get idle
/// 4. Work item's GetResult should return value
/// 4. Cancel the work item
/// 5. Work item's GetResult should return value
/// </summary>
[Test]
public void CancelCompletedWorkItem()
{
SmartThreadPool stp = new SmartThreadPool();
IWorkItemResult wir = stp.QueueWorkItem(
delegate(object state) { return 1; }
);
stp.WaitForIdle();
Assert.AreEqual(wir.GetResult(), 1);
wir.Cancel();
Assert.AreEqual(wir.GetResult(), 1);
stp.Shutdown();
}
/// <summary>
/// 1. Zero counter
/// 2. Create STP
/// 3. Queue 10 work items, that sleep and then increment the counter, into the STP
/// 4. Cancel the STP
/// 5. Make sure the counter is still zero
/// </summary>
[Test]
public void CancelSTPWorkItems()
{
// I don't use lock on the counter, since any number above 0 is a failure.
// In the worst case counter will be equal to 1 which is still not 0.
int counter = 0;
SmartThreadPool stp = new SmartThreadPool();
for (int i = 0; i < 10; i++)
{
stp.QueueWorkItem(
delegate(object state) { Thread.Sleep(500); ++counter; return null; }
);
}
Thread.Sleep(100);
stp.Cancel(true);
Assert.AreEqual(counter, 0);
stp.Shutdown();
}
/// <summary>
/// 1. Zero counter
/// 2. Create STP
/// 3. Create a WIG
/// 4. Queue 10 work items, that sleep and then increment the counter, into the WIG
/// 5. Cancel the WIG
/// 6. Wait for the WIG to become idle
/// 7. Make sure the counter is still zero
/// </summary>
[Test]
public void CancelWIGWorkItems()
{
// I don't use lock on the counter, since any number above 0 is a failure.
// In the worst case counter will be equal to 1 which is still not 0.
int counter = 0;
SmartThreadPool stp = new SmartThreadPool();
IWorkItemsGroup wig = stp.CreateWorkItemsGroup(10);
for (int i = 0; i < 10; i++)
{
wig.QueueWorkItem(
delegate(object state) { Thread.Sleep(500); ++counter; return null; }
);
}
Thread.Sleep(100);
wig.Cancel(true);
Assert.AreEqual(counter, 0);
stp.Shutdown();
}
/// <summary>
/// 1. Zero global counter
/// 2. Create STP
/// 3. Create a WIG1 in suspended mode
/// 4. Create a WIG2 in suspended mode
/// 5. Queue 5 work items, that increment the global counter, into the WIG1
/// 6. Queue 7 work items, that increment the global counter, into the WIG2
/// 7. Cancel the WIG1
/// 8. Start the WIG1
/// 9. Start the WIG2
/// 10. Wait for the STP to get idle
/// 11. Make sure the global counter is 7
/// </summary>
[Test]
public void Cancel1WIGof2WorkItems()
{
int counter1 = 0;
int counter2 = 0;
SmartThreadPool stp = new SmartThreadPool();
IWorkItemsGroup wig1 = stp.CreateWorkItemsGroup(3);
IWorkItemsGroup wig2 = stp.CreateWorkItemsGroup(3);
for (int i = 0; i < 3; i++)
{
wig1.QueueWorkItem(
delegate(object state) { Interlocked.Increment(ref counter1); Thread.Sleep(500); Interlocked.Increment(ref counter1); return null; }
);
}
for (int i = 0; i < 3; i++)
{
wig2.QueueWorkItem(
delegate(object state) { Thread.Sleep(500); Interlocked.Increment(ref counter2); return null; }
);
}
while (counter1 < 3)
{
Thread.Sleep(1);
}
wig1.Cancel(true);
stp.WaitForIdle();
Assert.AreEqual(3, counter1, "Cancelled WIG1");
Assert.AreEqual(3, counter2, "Normal WIG2");
stp.Shutdown();
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/*
private int _counter;
/// <summary>
/// Example of how to queue a work item and then cancel it while it is in the queue.
/// </summary>
[Test]
[ExpectedException(typeof(WorkItemCancelException))]
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);
// 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);
try
{
// 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())
{
// Retreiving result of a canceled work item throws WorkItemCancelException exception
wir2.GetResult();
}
}
}
finally
{
smartThreadPool.Shutdown();
}
}
/// <summary>
/// </summary>
[Test]
public void WorkItemCancelingAndInUseWorkerThreads()
{
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;
}
/// <summary>
/// Check within the work item if it was cancelled
/// </summary>
[Test]
public void SampleIfWorkItemCancelled()
{
_counter = 0;
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.StartSuspended = true;
// Create a SmartThreadPool with only one thread.
SmartThreadPool smartThreadPool = new SmartThreadPool(stpStartInfo);
IWorkItemResult[] wirs = new IWorkItemResult[100];
for (int i = 0; i < 100; ++i)
{
wirs[i] = smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoCheckForCancelledWorkItem), null);
}
for (int i = 0; i < 50; ++i)
{
wirs[i].Cancel();
}
smartThreadPool.Start();
smartThreadPool.WaitForIdle();
smartThreadPool.Shutdown();
Assert.AreEqual(50, _counter);
}
/// <summary>
/// 1. Create STP
/// 2. Queue work item into the STP
/// 4. Cancel the work item
/// 5. Work item doesn't check for cancel
/// 6. Work item quits
/// 7. Make sure the work item result is ok, and not an exception
/// </summary>
[Test]
public void TestWorkItemCancelledWorkItemOK()
{
// Create a SmartThreadPool with only one thread.
SmartThreadPool smartThreadPool = new SmartThreadPool();
AutoResetEvent start = new AutoResetEvent(false);
// Queue the work item
IWorkItemResult wir = smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoWaitForCancel), start);
// Wait for it to start executing
bool success = start.WaitOne(3000, false);
// Make sure it was started
Assert.IsTrue(success);
// Cancel the work item
wir.Cancel();
// Let it complete
start.Set();
// Wait for the work item to complete
smartThreadPool.WaitForIdle();
// Check the work item's result
// The work item started running after it was start its execution.
// Since the work item didn't sample the cancel, it was not aware that it
// was canceled. Therefore the result should be what the work item returned
// and not the cancel exeception
int result = (int)wir.GetResult(0, false);
smartThreadPool.Shutdown();
Assert.AreEqual(1, result);
}
/// <summary>
/// 1. Create STP
/// 2. Create WIG
/// 3. Queue work item into the WIG
/// 4. Cancel the work items in the WIG
/// 5. Work item doesn't check for cancel
/// 6. Work item quits
/// 7. Make sure the work item result is ok, and not an exception
/// </summary>
[Test]
public void TestWIGCancelledWorkItemOK()
{
// Create a SmartThreadPool with only one thread.
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup wig = smartThreadPool.CreateWorkItemsGroup(1);
AutoResetEvent start = new AutoResetEvent(false);
// Queue the work item
IWorkItemResult wir = wig.QueueWorkItem(new WorkItemCallback(this.DoWaitForCancel), start);
// Wait for it to start executing
bool success = start.WaitOne(3000, false);
// Make sure it was started
Assert.IsTrue(success);
// Cancel the work item
wig.Cancel();
// Let it complete
start.Set();
// Wait for the work item to complete
smartThreadPool.WaitForIdle();
// Check the work item's result
// The work item started running after it was start its execution.
// Since the work item didn't sample the cancel, it was not aware that it
// was canceled. Therefore the result should be what the work item returned
// and not the cancel exeception
int result = (int)wir.GetResult(0, false);
smartThreadPool.Shutdown();
Assert.AreEqual(1, result);
}
/// <summary>
/// 1. Create STP
/// 2. Queue work item into the STP
/// 3. Cancel the work items in the STP
/// 4. Work item doesn't check for cancel
/// 5. Work item quits
/// 6. Make sure the work item result is ok, and not an exception
/// </summary>
[Test]
public void TestSTPCancelledWorkItemOK()
{
// Create a SmartThreadPool with only one thread.
SmartThreadPool smartThreadPool = new SmartThreadPool();
AutoResetEvent start = new AutoResetEvent(false);
// Queue the work item
IWorkItemResult wir = smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoWaitForCancel), start);
// Wait for it to start executing
bool success = start.WaitOne(3000, false);
// Make sure it was started
Assert.IsTrue(success);
// Cancel the work item
smartThreadPool.Cancel();
// Let it complete
start.Set();
// Wait for the work item to complete
smartThreadPool.WaitForIdle();
// Check the work item's result
// The work item started running after it was start its execution.
// Since the work item didn't sample the cancel, it was not aware that it
// was canceled. Therefore the result should be what the work item returned
// and not the cancel exeception
int result = (int)wir.GetResult(0, false);
smartThreadPool.Shutdown();
Assert.AreEqual(1, result);
}
/// <summary>
/// 1. Create STP
/// 2. Queue work item
/// 3. Cancel the work item
/// 4. Work item checks the cancel and quits
/// 5. Make sure the work item result throws exception
/// </summary>
[Test]
[ExpectedException(typeof(WorkItemCancelException))]
public void TestWorkItemCanceledWorkItemCancelException()
{
// Create a SmartThreadPool with only one thread.
SmartThreadPool smartThreadPool = new SmartThreadPool();
AutoResetEvent start = new AutoResetEvent(false);
// Queue the work item
IWorkItemResult wir = smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoCheckForCancel), start);
// Wait for it to start executing
bool success = start.WaitOne(3000, false);
// Make sure it was started
Assert.IsTrue(success);
// Cancel the work item
wir.Cancel();
// Let it complete
start.Set();
// Wait for the work item to complete
smartThreadPool.WaitForIdle();
try
{
// Check the work item's result
// The work item started running after it was start its execution.
// The work item samples the cancel, therefore it is aware that it
// was canceled. Using the GetResult should throw the cancel exeception
wir.GetResult(0, false);
}
finally
{
smartThreadPool.Shutdown();
}
}
/// <summary>
/// 1. Create STP
/// 2. Create WIG
/// 3. Queue work item into the WIG
/// 4. Cancel the work items in the WIG
/// 5. Work item checks the cancel and quits
/// 6. Make sure the work item result throws exception
/// </summary>
[Test]
[ExpectedException(typeof(WorkItemCancelException))]
public void TestWIGCancelledWorkItemCancelException()
{
// Create a SmartThreadPool with only one thread.
SmartThreadPool smartThreadPool = new SmartThreadPool();
IWorkItemsGroup wig = smartThreadPool.CreateWorkItemsGroup(1);
AutoResetEvent start = new AutoResetEvent(false);
// Queue the work item
IWorkItemResult wir = wig.QueueWorkItem(new WorkItemCallback(this.DoCheckForCancel), start);
// Wait for it to start executing
bool success = start.WaitOne(3000, false);
// Make sure it was started
Assert.IsTrue(success);
// Cancel the work item
wig.Cancel();
// Let it complete
start.Set();
// Wait for the work item to complete
smartThreadPool.WaitForIdle();
try
{
// Check the work item's result
// The work item started running after it was start its execution.
// The work item samples the cancel, therefore it is aware that it
// was canceled. Using the GetResult should throw the cancel exeception
wir.GetResult(0, false);
}
finally
{
smartThreadPool.Shutdown();
}
}
/// <summary>
/// 1. Create STP
/// 3. Queue work item into the STP
/// 4. Cancel the work items in the STP
/// 5. Work item checks the cancel and quits
/// 6. Make sure the work item result throws exception
/// </summary>
[Test]
[ExpectedException(typeof(WorkItemCancelException))]
public void TestSTPCancelledWorkItemCancelException()
{
// Create a SmartThreadPool with only one thread.
SmartThreadPool smartThreadPool = new SmartThreadPool();
AutoResetEvent start = new AutoResetEvent(false);
// Queue the work item
IWorkItemResult wir = smartThreadPool.QueueWorkItem(new WorkItemCallback(this.DoCheckForCancel), start);
// Wait for it to start executing
bool success = start.WaitOne(3000, false);
// Make sure it was started
Assert.IsTrue(success);
// Cancel the work item
smartThreadPool.Cancel();
// Let it complete
start.Set();
// Wait for the work item to complete
smartThreadPool.WaitForIdle();
try
{
// Check the work item's result
// The work item started running after it was start its execution.
// The work item samples the cancel, therefore it is aware that it
// was canceled. Using the GetResult should throw the cancel exeception
wir.GetResult(0, false);
}
finally
{
smartThreadPool.Shutdown();
}
}
private object DoCheckForCancelledWorkItem(object state)
{
if (!SmartThreadPool.IsWorkItemCanceled)
{
Interlocked.Increment(ref _counter);
}
return null;
}
private object DoWaitForCancel(object state)
{
AutoResetEvent start = state as AutoResetEvent;
// Signal the test that the work item started
start.Set();
// Let the test run (or else the next line may reset the signaled event)
Thread.Sleep(10);
// Wait for the test to cancel the work item
start.WaitOne();
return 1;
}
private object DoCheckForCancel(object state)
{
AutoResetEvent start = state as AutoResetEvent;
// Signal the test that the work item started
start.Set();
// Let the test run (or else the next line may reset the signaled event)
Thread.Sleep(10);
// Wait for the test to cancel the work item
start.WaitOne();
// Sample if the work item was cancelled
bool cancelled = SmartThreadPool.IsWorkItemCanceled;
return 1;
}
*/
}
}
+156
View File
@@ -0,0 +1,156 @@
using System;
using System.Threading;
using System.Diagnostics;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for TestConcurrencyChanges.
/// </summary>
[TestFixture]
[Category("TestConcurrencyChanges")]
public class TestConcurrencyChanges
{
public TestConcurrencyChanges()
{
}
/// <summary>
/// Example of waiting for idle
/// </summary>
[Test]
public void TestMaxThreadsChange()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(1 * 1000, 1, 0);
bool success = false;
for (int i = 0; i < 100; ++i)
{
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
}
success = WaitForMaxThreadsValue(smartThreadPool, 1, 1 * 1000);
Assert.IsTrue(success);
smartThreadPool.MaxThreads = 5;
success = WaitForMaxThreadsValue(smartThreadPool, 5, 2 * 1000);
Assert.IsTrue(success);
smartThreadPool.MaxThreads = 25;
success = WaitForMaxThreadsValue(smartThreadPool, 25, 4 * 1000);
Assert.IsTrue(success);
smartThreadPool.MaxThreads = 10;
success = WaitForMaxThreadsValue(smartThreadPool, 10, 10 * 1000);
Assert.IsTrue(success);
smartThreadPool.Shutdown();
}
[Test]
public void TestMinThreadsChange()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(1 * 1000, 25, 0);
bool success = false;
success = WaitForMinThreadsValue(smartThreadPool, 0, 1 * 1000);
Assert.IsTrue(success);
smartThreadPool.MinThreads = 5;
success = WaitForMinThreadsValue(smartThreadPool, 5, 2 * 1000);
Assert.IsTrue(success);
smartThreadPool.MinThreads = 25;
success = WaitForMinThreadsValue(smartThreadPool, 25, 4 * 1000);
Assert.IsTrue(success);
smartThreadPool.MinThreads = 10;
success = WaitForMinThreadsValue(smartThreadPool, 10, 10 * 1000);
Assert.IsTrue(success);
smartThreadPool.Shutdown();
}
/// <summary>
/// Example of waiting for idle
/// </summary>
[Test]
public void TestConcurrencyChange()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(10 * 1000, 1, 0);
bool success = false;
for (int i = 0; i < 100; ++i)
{
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
}
smartThreadPool.Concurrency = 1;
success = WaitForMaxThreadsValue(smartThreadPool, 1, 1 * 1000);
Assert.IsTrue(success);
smartThreadPool.Concurrency = 5;
success = WaitForMaxThreadsValue(smartThreadPool, 5, 2 * 1000);
Assert.IsTrue(success);
smartThreadPool.Concurrency = 25;
success = WaitForMaxThreadsValue(smartThreadPool, 25, 4 * 1000);
Assert.IsTrue(success);
smartThreadPool.Concurrency = 10;
success = WaitForMaxThreadsValue(smartThreadPool, 10, 10 * 1000);
Assert.IsTrue(success);
smartThreadPool.Shutdown();
}
private bool WaitForMaxThreadsValue(SmartThreadPool smartThreadPool, int maxThreadsCount, int timeout)
{
DateTime end = DateTime.Now + new TimeSpan(0, 0, 0, 0, timeout);
bool success = false;
while(DateTime.Now <= end && !success)
{
success = (smartThreadPool.InUseThreads == maxThreadsCount);
Thread.Sleep(10);
}
return success;
}
private bool WaitForMinThreadsValue(SmartThreadPool smartThreadPool, int minThreadsCount, int timeout)
{
DateTime end = DateTime.Now + new TimeSpan(0, 0, 0, 0, timeout);
bool success = false;
while (DateTime.Now <= end && !success)
{
success = (smartThreadPool.ActiveThreads == minThreadsCount);
Thread.Sleep(10);
}
return success;
}
private int x = 0;
private object DoSomeWork(object state)
{
Debug.WriteLine(Interlocked.Increment(ref x));
Thread.Sleep(1000);
return 1;
}
}
}
+246
View File
@@ -0,0 +1,246 @@
using System;
using Amib.Threading;
using NUnit.Framework;
using System.Net;
namespace STPTests
{
/// <summary>
/// Summary description for TestFalseFillStateWithArgs.
/// </summary>
[TestFixture]
[Category("TestFalseFillStateWithArgs")]
public class TestFalseFillStateWithArgs
{
private SmartThreadPool _stp;
private IWorkItemsGroup _wig;
[SetUp]
public void Init()
{
_stp = new SmartThreadPool();
_wig = _stp.CreateWorkItemsGroup(10);
}
[TearDown]
public void Fini()
{
_stp.WaitForIdle();
_stp.Shutdown();
}
[Test]
public void STPActionT0()
{
IWorkItemResult wir = _stp.QueueWorkItem(Action0);
Assert.IsNull(wir.State);
}
[Test]
public void STPActionT1()
{
IWorkItemResult wir = _stp.QueueWorkItem(Action1, 17);
Assert.IsNull(wir.State);
}
[Test]
public void STPActionT2()
{
IWorkItemResult wir = _stp.QueueWorkItem(Action2, 'a', "bla bla");
Assert.IsNull(wir.State);
}
[Test]
public void STPActionT3()
{
char[] chars = new char[] { 'a', 'b' };
object obj = new object();
IWorkItemResult wir = _stp.QueueWorkItem(Action3, true, chars, obj);
Assert.IsNull(wir.State);
}
[Test]
public void STPActionT4()
{
IntPtr p = new IntPtr(int.MaxValue);
Guid guid = Guid.NewGuid();
IPAddress ip = IPAddress.Parse("1.2.3.4");
IWorkItemResult wir = _stp.QueueWorkItem(Action4, long.MinValue, p, ip, guid);
Assert.IsNull(wir.State);
}
[Test]
public void STPFuncT0()
{
IWorkItemResult<int> wir = _stp.QueueWorkItem(new Func<int>(Func0));
Assert.IsNull(wir.State);
}
[Test]
public void STPFuncT1()
{
IWorkItemResult<bool> wir = _stp.QueueWorkItem(new Func<int, bool>(Func1), 17);
Assert.IsNull(wir.State);
}
[Test]
public void STPFuncT2()
{
IWorkItemResult<string> wir = _stp.QueueWorkItem(new Func<char, string, string>(Func2), 'a', "bla bla");
Assert.IsNull(wir.State);
}
[Test]
public void STPFuncT3()
{
char[] chars = new char[] { 'a', 'b' };
object obj = new object();
IWorkItemResult<char> wir = _stp.QueueWorkItem(new Func<bool, char[], object, char>(Func3), true, chars, obj);
Assert.IsNull(wir.State);
}
[Test]
public void STPFuncT4()
{
IntPtr p = new IntPtr(int.MaxValue);
Guid guid = Guid.NewGuid();
IPAddress ip = IPAddress.Parse("1.2.3.4");
IWorkItemResult<IPAddress> wir = _stp.QueueWorkItem(new Func<long, IntPtr, IPAddress, Guid, IPAddress>(Func4), long.MinValue, p, ip, guid);
Assert.IsNull(wir.State);
}
[Test]
public void WIGActionT0()
{
IWorkItemResult wir = _wig.QueueWorkItem(Action0);
Assert.IsNull(wir.State);
}
[Test]
public void WIGActionT1()
{
IWorkItemResult wir = _wig.QueueWorkItem(Action1, 17);
Assert.IsNull(wir.State);
}
[Test]
public void WIGActionT2()
{
IWorkItemResult wir = _wig.QueueWorkItem(Action2, 'a', "bla bla");
Assert.IsNull(wir.State);
}
[Test]
public void WIGActionT3()
{
char[] chars = new char[] { 'a', 'b' };
object obj = new object();
IWorkItemResult wir = _wig.QueueWorkItem(Action3, true, chars, obj);
Assert.IsNull(wir.State);
}
[Test]
public void WIGActionT4()
{
IntPtr p = new IntPtr(int.MaxValue);
Guid guid = Guid.NewGuid();
IPAddress ip = IPAddress.Parse("1.2.3.4");
IWorkItemResult wir = _wig.QueueWorkItem(Action4, long.MinValue, p, ip, guid);
Assert.IsNull(wir.State);
}
[Test]
public void WIGFuncT0()
{
IWorkItemResult<int> wir = _wig.QueueWorkItem(new Func<int>(Func0));
Assert.IsNull(wir.State);
}
[Test]
public void WIGFuncT1()
{
IWorkItemResult<bool> wir = _wig.QueueWorkItem(new Func<int, bool>(Func1), 17);
Assert.IsNull(wir.State);
}
[Test]
public void WIGFuncT2()
{
IWorkItemResult<string> wir = _wig.QueueWorkItem(new Func<char, string, string>(Func2), 'a', "bla bla");
Assert.IsNull(wir.State);
}
[Test]
public void WIGFuncT3()
{
char[] chars = new char[] { 'a', 'b' };
object obj = new object();
IWorkItemResult<char> wir = _wig.QueueWorkItem(new Func<bool, char[], object, char>(Func3), true, chars, obj);
Assert.IsNull(wir.State);
}
[Test]
public void WIGFuncT4()
{
IntPtr p = new IntPtr(int.MaxValue);
Guid guid = Guid.NewGuid();
IPAddress ip = IPAddress.Parse("1.2.3.4");
IWorkItemResult<IPAddress> wir = _wig.QueueWorkItem(new Func<long, IntPtr, IPAddress, Guid, IPAddress>(Func4), long.MinValue, p, ip, guid);
Assert.IsNull(wir.State);
}
private void Action0()
{
}
private void Action1(int p1)
{
}
private void Action2(char p1, string p2)
{
}
private void Action3(bool p1, char[] p2, object p3)
{
}
private void Action4(long p1, IntPtr p2, IPAddress p3, Guid p4)
{
}
private int Func0()
{
return 0;
}
private bool Func1(int p1)
{
return true;
}
private string Func2(char p1, string p2)
{
return "value";
}
private char Func3(bool p1, char[] p2, object p3)
{
return 'z';
}
private IPAddress Func4(long p1, IntPtr p2, IPAddress p3, Guid p4)
{
return IPAddress.None;
}
}
}
+207
View File
@@ -0,0 +1,207 @@
using System;
using Amib.Threading;
using NUnit.Framework;
using System.Net;
namespace STPTests
{
/// <summary>
/// Summary description for TestFillStateWithArgs.
/// </summary>
[TestFixture]
[Category("TestFillStateWithArgs")]
public class TestFillStateWithArgs
{
private SmartThreadPool _stp;
[SetUp]
public void Init()
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.FillStateWithArgs = true;
_stp = new SmartThreadPool(stpStartInfo);
}
[TearDown]
public void Fini()
{
_stp.WaitForIdle();
_stp.Shutdown();
}
[Test]
public void ActionT0()
{
IWorkItemResult wir = _stp.QueueWorkItem(Action0);
Assert.IsNull(wir.State);
}
[Test]
public void ActionT1()
{
IWorkItemResult wir = _stp.QueueWorkItem(Action1, 17);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 1);
Assert.AreEqual(args[0], 17);
}
[Test]
public void ActionT2()
{
IWorkItemResult wir = _stp.QueueWorkItem(Action2, 'a', "bla bla");
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 2);
Assert.AreEqual(args[0], 'a');
Assert.AreEqual(args[1], "bla bla");
}
[Test]
public void ActionT3()
{
char[] chars = new char[] {'a', 'b'};
object obj = new object();
IWorkItemResult wir = _stp.QueueWorkItem(Action3, true, chars, obj);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 3);
Assert.AreEqual(args[0], true);
Assert.AreEqual(args[1], chars);
Assert.AreEqual(args[2], obj);
}
[Test]
public void ActionT4()
{
IntPtr p = new IntPtr(int.MaxValue);
Guid guid = Guid.NewGuid();
IPAddress ip = IPAddress.Parse("1.2.3.4");
IWorkItemResult wir = _stp.QueueWorkItem(Action4, long.MinValue, p, ip, guid);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 4);
Assert.AreEqual(args[0], long.MinValue);
Assert.AreEqual(args[1], p);
Assert.AreEqual(args[2], ip);
Assert.AreEqual(args[3], guid);
}
[Test]
public void FuncT0()
{
IWorkItemResult<int> wir = _stp.QueueWorkItem(new Func<int>(Func0));
Assert.AreEqual(wir.State, null);
}
[Test]
public void FuncT1()
{
IWorkItemResult<bool> wir = _stp.QueueWorkItem(new Func<int, bool>(Func1), 17);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 1);
Assert.AreEqual(args[0], 17);
}
[Test]
public void FuncT2()
{
IWorkItemResult<string> wir = _stp.QueueWorkItem(new Func<char, string, string>(Func2), 'a', "bla bla");
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 2);
Assert.AreEqual(args[0], 'a');
Assert.AreEqual(args[1], "bla bla");
}
[Test]
public void FuncT3()
{
char[] chars = new char[] { 'a', 'b' };
object obj = new object();
IWorkItemResult<char> wir = _stp.QueueWorkItem(new Func<bool, char[], object, char>(Func3), true, chars, obj);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 3);
Assert.AreEqual(args[0], true);
Assert.AreEqual(args[1], chars);
Assert.AreEqual(args[2], obj);
}
[Test]
public void FuncT4()
{
IntPtr p = new IntPtr(int.MaxValue);
Guid guid = Guid.NewGuid();
IPAddress ip = IPAddress.Parse("1.2.3.4");
IWorkItemResult<IPAddress> wir = _stp.QueueWorkItem(new Func<long, IntPtr, IPAddress, Guid, IPAddress>(Func4), long.MinValue, p, ip, guid);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 4);
Assert.AreEqual(args[0], long.MinValue);
Assert.AreEqual(args[1], p);
Assert.AreEqual(args[2], ip);
Assert.AreEqual(args[3], guid);
}
private void Action0()
{
}
private void Action1(int p1)
{
}
private void Action2(char p1, string p2)
{
}
private void Action3(bool p1, char [] p2, object p3)
{
}
private void Action4(long p1, IntPtr p2, IPAddress p3, Guid p4)
{
}
private int Func0()
{
return 0;
}
private bool Func1(int p1)
{
return true;
}
private string Func2(char p1, string p2)
{
return "value";
}
private char Func3(bool p1, char[] p2, object p3)
{
return 'z';
}
private IPAddress Func4(long p1, IntPtr p2, IPAddress p3, Guid p4)
{
return IPAddress.None;
}
}
}
+43
View File
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Text;
using Amib.Threading;
using NUnit.Framework;
namespace STPTests
{
/// <summary>
/// Summary description for TestCancel.
/// </summary>
[TestFixture]
[Category("TestFuncT")]
public class TestFuncT
{
[Test]
public void FuncT()
{
SmartThreadPool stp = new SmartThreadPool();
IWorkItemResult<int> wir =
stp.QueueWorkItem(new Func<int, int>(f), 1);
int y = wir.GetResult();
Assert.AreEqual(y, 2);
try
{
wir.GetResult();
}
finally
{
stp.Shutdown();
}
}
private int f(int x)
{
return x + 1;
}
}
}
+112
View File
@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Text;
using Amib.Threading;
using NUnit.Framework;
namespace SmartThreadPoolTests
{
/// <summary>
/// Summary description for TestCancel.
/// </summary>
[TestFixture]
[Category("TestFuncT")]
public class TestFuncT
{
private SmartThreadPool _stp;
[SetUp]
public void Init()
{
_stp = new SmartThreadPool();
}
[TearDown]
public void Fini()
{
_stp.Shutdown();
}
[Test]
public void FuncT0()
{
IWorkItemResult<int> wir = _stp.QueueWorkItem(new Func<int>(MaxInt));
int result = wir.GetResult();
Assert.AreEqual(result, int.MaxValue);
}
[Test]
public void FuncT1()
{
IWorkItemResult<bool> wir = _stp.QueueWorkItem(new Func<bool, bool>(Not), true);
bool result = wir.Result;
Assert.AreEqual(result, false);
}
[Test]
public void FuncT2()
{
IWorkItemResult<string> wir = _stp.QueueWorkItem(new Func<string, string, string>(string.Concat), "ABC", "xyz");
string result = wir.Result;
Assert.AreEqual(result, "ABCxyz");
}
[Test]
public void FuncT3()
{
IWorkItemResult<string> wir = _stp.QueueWorkItem(new Func<string, int, int, string>(Substring), "ABCDEF", 1, 2);
string result = wir.Result;
Assert.AreEqual(result, "BC");
}
[Test]
public void FuncT4()
{
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IWorkItemResult<int[]> wir = _stp.QueueWorkItem(new Func<int[], int, int, int, int[]>(Subarray), numbers, 1, 2, 3);
int[] result = wir.Result;
Assert.AreEqual(result, new int[] { 2, 3, 2, 3, 2, 3, });
}
private int MaxInt()
{
return int.MaxValue;
}
private bool Not(bool flag)
{
return !flag;
}
private string Substring(string s, int startIndex, int length)
{
return s.Substring(startIndex, length);
}
private int[] Subarray(int[] numbers, int startIndex, int length, int repeat)
{
int[] result = new int[length * repeat];
for (int i = 0; i < repeat; i++)
{
for (int j = 0; j < length; j++)
{
result[i * length + j] = numbers[startIndex + j];
}
}
return result;
}
}
}
+43 -134
View File
@@ -42,144 +42,52 @@ namespace SmartThreadPoolTests
/// Example of how to queue a work item and then wait on a timeout for the result.
/// </summary>
[Test]
public void Timeout()
[ExpectedException(typeof(WorkItemTimeoutException))]
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;
}
try
{
wir.GetResult(500, true);
}
finally
{
smartThreadPool.Shutdown();
}
}
smartThreadPool.Shutdown();
/// <summary>
/// Example of how to interrupt the waiting for a work item to complete.
/// </summary>
[Test]
[ExpectedException(typeof(WorkItemTimeoutException))]
public void WorkItemWaitCanceling()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
Assert.IsTrue(success);
}
ManualResetEvent cancelWaitHandle = new ManualResetEvent(false);
/// <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);
}
// 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);
}
finally
{
smartThreadPool.Shutdown();
}
}
private object DoSomeWork(object state)
{
@@ -187,12 +95,13 @@ namespace SmartThreadPoolTests
return 1;
}
private object SignalCancel(object state)
{
ManualResetEvent cancelWaitHandle = state as ManualResetEvent;
Thread.Sleep(250);
cancelWaitHandle.Set();
return null;
}
private object SignalCancel(object state)
{
ManualResetEvent cancelWaitHandle = state as ManualResetEvent;
Thread.Sleep(250);
cancelWaitHandle.Set();
return null;
}
}
}
+68
View File
@@ -228,5 +228,73 @@ namespace SmartThreadPoolTests
Thread.Sleep(1000);
return 1;
}
[Test]
public void WaitAllT()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = true;
IWorkItemResult<int>[] wirs = new IWorkItemResult<int>[5];
for (int i = 0; i < wirs.Length; ++i)
{
wirs[i] = smartThreadPool.QueueWorkItem(new Func<int, int, int>(Math.Min), i, i + 1);
}
SmartThreadPool.WaitAll(wirs);
for (int i = 0; i < wirs.Length; ++i)
{
if (!wirs[i].IsCompleted)
{
success = false;
break;
}
int result = wirs[i].GetResult();
if (i != result)
{
success = false;
break;
}
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
[Test]
public void WaitAnyT()
{
SmartThreadPool smartThreadPool = new SmartThreadPool();
bool success = false;
IWorkItemResult<int>[] wirs = new IWorkItemResult<int>[5];
for (int i = 0; i < wirs.Length; ++i)
{
wirs[i] = smartThreadPool.QueueWorkItem(new Func<int, int, int>(Math.Max), i, i - 1);
}
int index = SmartThreadPool.WaitAny(wirs);
if (wirs[index].IsCompleted)
{
int result = wirs[index].GetResult();
if (index == result)
{
success = true;
}
}
smartThreadPool.Shutdown();
Assert.IsTrue(success);
}
}
}
+98
View File
@@ -0,0 +1,98 @@
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// Tests for QueueWorkItem.
/// </summary>
[TestFixture]
[Category("TestQueueWorkItem")]
public class TestQueueWorkItem
{
private SmartThreadPool _stp;
[SetUp]
public void Init()
{
_stp = new SmartThreadPool();
}
[TearDown]
public void Fini()
{
_stp.Shutdown();
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback);
[Test]
public void TestQueueWorkItemCall()
{
QueueWorkItemHelper.TestQueueWorkItemCall(_stp);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
[Test]
public void TestQueueWorkItemCallPrio()
{
QueueWorkItemHelper.TestQueueWorkItemCallPrio(_stp);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
[Test]
public void TestQueueWorkItemCallStat()
{
QueueWorkItemHelper.TestQueueWorkItemCallStat(_stp);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
[Test]
public void TestQueueWorkItemCallStatPrio()
{
QueueWorkItemHelper.TestQueueWorkItemCallStatPrio(_stp);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
[Test]
public void TestQueueWorkItemCallStatPost()
{
QueueWorkItemHelper.TestQueueWorkItemCallStatPost(_stp);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
[Test]
public void TestQueueWorkItemCallStatPostPrio()
{
QueueWorkItemHelper.TestQueueWorkItemCallStatPostPrio(_stp);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
[Test]
public void TestQueueWorkItemCallStatPostPflg()
{
QueueWorkItemHelper.TestQueueWorkItemCallStatPostPflg(_stp);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
[Test]
public void TestQueueWorkItemCallStatPostPflgPrio()
{
QueueWorkItemHelper.TestQueueWorkItemCallStatPostPflgPrio(_stp);
}
//IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
[Test]
public void TestQueueWorkItemInfoCall()
{
QueueWorkItemHelper.TestQueueWorkItemInfoCall(_stp);
}
//IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
[Test]
public void TestQueueWorkItemInfoCallStat()
{
QueueWorkItemHelper.TestQueueWorkItemInfoCallStat(_stp);
}
}
}
+99
View File
@@ -0,0 +1,99 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
{
/// <summary>
/// </summary>
[TestFixture]
[Category("TestThreadsCreate")]
public class TestThreadsCreate
{
private bool _initSuccess;
private bool _workItemSuccess;
private bool _termSuccess;
private void ClearResults()
{
_initSuccess = false;
_workItemSuccess = false;
_termSuccess = false;
}
[Test]
public void TestThreadsEvents()
{
ClearResults();
SmartThreadPool stp = new SmartThreadPool();
stp.OnThreadInitialization += new ThreadInitializationHandler(OnInitialization);
stp.OnThreadTermination += new ThreadTerminationHandler(OnTermination);
stp.QueueWorkItem(new WorkItemCallback(DoSomeWork), null);
stp.WaitForIdle();
stp.Shutdown();
Assert.IsTrue(_initSuccess);
Assert.IsTrue(_workItemSuccess);
Assert.IsTrue(_termSuccess);
}
public void OnInitialization()
{
ThreadContextState.Current.Counter = 1234;
_initSuccess = true;
}
private object DoSomeWork(object state)
{
int counter = ThreadContextState.Current.Counter;
_workItemSuccess = (1234 == counter);
ThreadContextState.Current.Counter = 1111;
return 1;
}
public void OnTermination()
{
int counter = ThreadContextState.Current.Counter;
_termSuccess = (1111 == counter);
}
}
internal class ThreadContextState
{
// Each thread will have its own ThreadContextState object
[ThreadStatic]
private static ThreadContextState _threadContextState;
private int _counter = 0;
public int Counter
{
get { return _counter; }
set { _counter = value; }
}
// Static member so it can be used anywhere in code of the work item method
public static ThreadContextState Current
{
get
{
// If the _threadContextState is null then it was not yet initialized
// for this thread.
if (null == _threadContextState)
{
// Create a ThreadContextState object
_threadContextState = new ThreadContextState();
}
return _threadContextState;
}
}
}
}
+126
View File
@@ -0,0 +1,126 @@
using Amib.Threading;
using NUnit.Framework;
namespace WorkItemsGroupTests
{
/// <summary>
/// Summary description for TestCancel.
/// </summary>
[TestFixture]
[Category("TestWIGActionT")]
public class TestWIGActionT
{
private SmartThreadPool _stp;
private IWorkItemsGroup _wig;
private object _result;
[SetUp]
public void Init()
{
_stp = new SmartThreadPool();
_wig = _stp.CreateWorkItemsGroup(10);
}
[TearDown]
public void Fini()
{
_stp.Shutdown();
}
[Test]
public void ActionT0()
{
_result = null;
IWorkItemResult wir = _wig.QueueWorkItem(MaxInt);
wir.GetResult();
Assert.AreEqual(_result, int.MaxValue);
}
[Test]
public void ActionT1()
{
_result = null;
IWorkItemResult wir = _wig.QueueWorkItem(Not, true);
wir.GetResult();
Assert.AreEqual(_result, false);
}
[Test]
public void ActionT2()
{
_result = null;
IWorkItemResult wir = _wig.QueueWorkItem(Concat, "ABC", "xyz");
wir.GetResult();
Assert.AreEqual(_result, "ABCxyz");
}
[Test]
public void ActionT3()
{
_result = null;
IWorkItemResult wir = _wig.QueueWorkItem(Substring, "ABCDEF", 1, 2);
wir.GetResult();
Assert.AreEqual(_result, "BC");
}
[Test]
public void ActionT4()
{
_result = null;
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IWorkItemResult wir = _wig.QueueWorkItem(Subarray, numbers, 1, 2, 3);
wir.GetResult();
Assert.AreEqual(_result, new int[] { 2, 3, 2, 3, 2, 3, });
}
private void MaxInt()
{
_result = int.MaxValue;
}
private void Not(bool flag)
{
_result = !flag;
}
private void Concat(string s1, string s2)
{
_result = s1 + s2;
}
private void Substring(string s, int startIndex, int length)
{
_result = s.Substring(startIndex, length);
}
private void Subarray(int[] numbers, int startIndex, int length, int repeat)
{
int[] result = new int[length * repeat];
for (int i = 0; i < repeat; i++)
{
for (int j = 0; j < length; j++)
{
result[i * length + j] = numbers[startIndex + j];
}
}
_result = result;
}
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ using NUnit.Framework;
using Amib.Threading;
namespace SmartThreadPoolTests
namespace WorkItemsGroupTests
{
/// <summary>
/// Summary description for TestWIGConcurrency.
+213
View File
@@ -0,0 +1,213 @@
using System;
using System.Threading;
using System.Diagnostics;
using NUnit.Framework;
using Amib.Threading;
namespace WorkItemsGroupTests
{
/// <summary>
/// Summary description for TestWIGConcurrencyChanges.
/// </summary>
[TestFixture]
[Category("TestWIGConcurrencyChanges")]
public class TestWIGConcurrencyChanges
{
public TestWIGConcurrencyChanges()
{
}
/// <summary>
/// Example of waiting for idle
/// </summary>
[Test]
public void TestWIGConcurrencyChange1WIG()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 1, 0);
Assert.IsTrue(0 == smartThreadPool.WaitingCallbacks);
PauseSTP(smartThreadPool);
Thread.Sleep(100);
Assert.IsTrue(0 == smartThreadPool.WaitingCallbacks);
IWorkItemsGroup wig = smartThreadPool.CreateWorkItemsGroup(1);
wig.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
Assert.IsTrue(1 == smartThreadPool.WaitingCallbacks);
wig.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
Assert.IsTrue(1 == smartThreadPool.WaitingCallbacks);
wig.Concurrency = 2;
Thread.Sleep(100);
Assert.IsTrue(2 == smartThreadPool.WaitingCallbacks);
ResumeSTP(smartThreadPool);
Thread.Sleep(100);
Assert.IsTrue(0 == smartThreadPool.WaitingCallbacks);
PauseSTP(smartThreadPool);
wig.Concurrency = 1;
wig.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
Assert.IsTrue(1 == smartThreadPool.WaitingCallbacks);
wig.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
Assert.IsTrue(1 == smartThreadPool.WaitingCallbacks);
ResumeSTP(smartThreadPool);
Thread.Sleep(100);
Assert.IsTrue(0 == smartThreadPool.WaitingCallbacks);
smartThreadPool.Shutdown();
}
/// <summary>
/// Example of waiting for idle
/// </summary>
[Test]
public void TestWIGConcurrencyChange2WIGs()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(10 * 1000, 2, 0);
Assert.IsTrue(0 == smartThreadPool.WaitingCallbacks);
PauseSTP(smartThreadPool);
PauseSTP(smartThreadPool);
Thread.Sleep(100);
Assert.IsTrue(0 == smartThreadPool.WaitingCallbacks);
IWorkItemsGroup wig1 = smartThreadPool.CreateWorkItemsGroup(1);
IWorkItemsGroup wig2 = smartThreadPool.CreateWorkItemsGroup(1);
wig1.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
Assert.IsTrue(1 == smartThreadPool.WaitingCallbacks);
wig2.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
Assert.IsTrue(2 == smartThreadPool.WaitingCallbacks);
wig1.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
Assert.IsTrue(2 == smartThreadPool.WaitingCallbacks);
wig2.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
Assert.IsTrue(2 == smartThreadPool.WaitingCallbacks);
wig1.Concurrency = 2;
Thread.Sleep(100);
Assert.IsTrue(3 == smartThreadPool.WaitingCallbacks);
wig2.Concurrency = 2;
Thread.Sleep(100);
Assert.IsTrue(4 == smartThreadPool.WaitingCallbacks);
ResumeSTP(smartThreadPool);
Thread.Sleep(100);
Assert.IsTrue(0 == smartThreadPool.WaitingCallbacks);
PauseSTP(smartThreadPool);
PauseSTP(smartThreadPool);
Thread.Sleep(100);
wig1.Concurrency = 1;
wig1.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
Assert.IsTrue(1 == smartThreadPool.WaitingCallbacks);
wig2.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), null);
Assert.IsTrue(2 == smartThreadPool.WaitingCallbacks);
ResumeSTP(smartThreadPool);
Thread.Sleep(100);
Assert.IsTrue(0 == smartThreadPool.WaitingCallbacks);
smartThreadPool.Shutdown();
}
private void PauseSTP(SmartThreadPool stp)
{
_pauseSTP.Reset();
stp.QueueWorkItem(
new WorkItemCallback(this.DoPauseSTP),
null);
}
private void ResumeSTP(SmartThreadPool stp)
{
_pauseSTP.Set();
}
private ManualResetEvent _pauseSTP = new ManualResetEvent(false);
private object DoPauseSTP(object state)
{
_pauseSTP.WaitOne();
return 1;
}
private object DoSomeWork(object state)
{
return 1;
}
/*
/// <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;
}
*/
}
}
+210
View File
@@ -0,0 +1,210 @@
using System;
using Amib.Threading;
using NUnit.Framework;
using System.Net;
namespace STPTests
{
/// <summary>
/// Summary description for TestWIGFillStateWithArgs.
/// </summary>
[TestFixture]
[Category("TestWIGFillStateWithArgs")]
public class TestWIGFillStateWithArgs
{
private SmartThreadPool _stp;
private IWorkItemsGroup _wig;
[SetUp]
public void Init()
{
_stp = new SmartThreadPool();
WIGStartInfo wigStartInfo = new WIGStartInfo();
wigStartInfo.FillStateWithArgs = true;
_wig = _stp.CreateWorkItemsGroup(10, wigStartInfo);
}
[TearDown]
public void Fini()
{
_stp.WaitForIdle();
_stp.Shutdown();
}
[Test]
public void ActionT0()
{
IWorkItemResult wir = _wig.QueueWorkItem(Action0);
Assert.IsNull(wir.State);
}
[Test]
public void ActionT1()
{
IWorkItemResult wir = _wig.QueueWorkItem(Action1, 17);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 1);
Assert.AreEqual(args[0], 17);
}
[Test]
public void ActionT2()
{
IWorkItemResult wir = _wig.QueueWorkItem(Action2, 'a', "bla bla");
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 2);
Assert.AreEqual(args[0], 'a');
Assert.AreEqual(args[1], "bla bla");
}
[Test]
public void ActionT3()
{
char[] chars = new char[] { 'a', 'b' };
object obj = new object();
IWorkItemResult wir = _wig.QueueWorkItem(Action3, true, chars, obj);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 3);
Assert.AreEqual(args[0], true);
Assert.AreEqual(args[1], chars);
Assert.AreEqual(args[2], obj);
}
[Test]
public void ActionT4()
{
IntPtr p = new IntPtr(int.MaxValue);
Guid guid = Guid.NewGuid();
IPAddress ip = IPAddress.Parse("1.2.3.4");
IWorkItemResult wir = _wig.QueueWorkItem(Action4, long.MinValue, p, ip, guid);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 4);
Assert.AreEqual(args[0], long.MinValue);
Assert.AreEqual(args[1], p);
Assert.AreEqual(args[2], ip);
Assert.AreEqual(args[3], guid);
}
[Test]
public void FuncT0()
{
IWorkItemResult<int> wir = _wig.QueueWorkItem(new Func<int>(Func0));
Assert.AreEqual(wir.State, null);
}
[Test]
public void FuncT1()
{
IWorkItemResult<bool> wir = _wig.QueueWorkItem(new Func<int, bool>(Func1), 17);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 1);
Assert.AreEqual(args[0], 17);
}
[Test]
public void FuncT2()
{
IWorkItemResult<string> wir = _wig.QueueWorkItem(new Func<char, string, string>(Func2), 'a', "bla bla");
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 2);
Assert.AreEqual(args[0], 'a');
Assert.AreEqual(args[1], "bla bla");
}
[Test]
public void FuncT3()
{
char[] chars = new char[] { 'a', 'b' };
object obj = new object();
IWorkItemResult<char> wir = _wig.QueueWorkItem(new Func<bool, char[], object, char>(Func3), true, chars, obj);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 3);
Assert.AreEqual(args[0], true);
Assert.AreEqual(args[1], chars);
Assert.AreEqual(args[2], obj);
}
[Test]
public void FuncT4()
{
IntPtr p = new IntPtr(int.MaxValue);
Guid guid = Guid.NewGuid();
IPAddress ip = IPAddress.Parse("1.2.3.4");
IWorkItemResult<IPAddress> wir = _wig.QueueWorkItem(new Func<long, IntPtr, IPAddress, Guid, IPAddress>(Func4), long.MinValue, p, ip, guid);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 4);
Assert.AreEqual(args[0], long.MinValue);
Assert.AreEqual(args[1], p);
Assert.AreEqual(args[2], ip);
Assert.AreEqual(args[3], guid);
}
private void Action0()
{
}
private void Action1(int p1)
{
}
private void Action2(char p1, string p2)
{
}
private void Action3(bool p1, char[] p2, object p3)
{
}
private void Action4(long p1, IntPtr p2, IPAddress p3, Guid p4)
{
}
private int Func0()
{
return 0;
}
private bool Func1(int p1)
{
return true;
}
private string Func2(char p1, string p2)
{
return "value";
}
private char Func3(bool p1, char[] p2, object p3)
{
return 'z';
}
private IPAddress Func4(long p1, IntPtr p2, IPAddress p3, Guid p4)
{
return IPAddress.None;
}
}
}
+207
View File
@@ -0,0 +1,207 @@
using System;
using Amib.Threading;
using NUnit.Framework;
using System.Net;
namespace STPTests
{
/// <summary>
/// Summary description for TestFillStateWithParams.
/// </summary>
[TestFixture]
[Category("TestFillStateWithParams")]
public class TestFillStateWithParams
{
private SmartThreadPool _stp;
[SetUp]
public void Init()
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.FillStateWithParams = true;
_stp = new SmartThreadPool(stpStartInfo);
}
[TearDown]
public void Fini()
{
_stp.WaitForIdle();
_stp.Shutdown();
}
[Test]
public void ActionT0()
{
IWorkItemResult wir = _stp.QueueWorkItem(Action0);
Assert.IsNull(wir.State);
}
[Test]
public void ActionT1()
{
IWorkItemResult wir = _stp.QueueWorkItem(Action1, 17);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 1);
Assert.AreEqual(args[0], 17);
}
[Test]
public void ActionT2()
{
IWorkItemResult wir = _stp.QueueWorkItem(Action2, 'a', "bla bla");
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 2);
Assert.AreEqual(args[0], 'a');
Assert.AreEqual(args[1], "bla bla");
}
[Test]
public void ActionT3()
{
char[] chars = new char[] {'a', 'b'};
object obj = new object();
IWorkItemResult wir = _stp.QueueWorkItem(Action3, true, chars, obj);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 3);
Assert.AreEqual(args[0], true);
Assert.AreEqual(args[1], chars);
Assert.AreEqual(args[2], obj);
}
[Test]
public void ActionT4()
{
IntPtr p = new IntPtr(int.MaxValue);
Guid guid = Guid.NewGuid();
IPAddress ip = IPAddress.Parse("1.2.3.4");
IWorkItemResult wir = _stp.QueueWorkItem(Action4, long.MinValue, p, ip, guid);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 4);
Assert.AreEqual(args[0], long.MinValue);
Assert.AreEqual(args[1], p);
Assert.AreEqual(args[2], ip);
Assert.AreEqual(args[3], guid);
}
[Test]
public void FuncT0()
{
IWorkItemResult<int> wir = _stp.QueueWorkItem(new Func<int>(Func0));
Assert.AreEqual(wir.State, null);
}
[Test]
public void FuncT1()
{
IWorkItemResult<bool> wir = _stp.QueueWorkItem(new Func<int, bool>(Func1), 17);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 1);
Assert.AreEqual(args[0], 17);
}
[Test]
public void FuncT2()
{
IWorkItemResult<string> wir = _stp.QueueWorkItem(new Func<char, string, string>(Func2), 'a', "bla bla");
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 2);
Assert.AreEqual(args[0], 'a');
Assert.AreEqual(args[1], "bla bla");
}
[Test]
public void FuncT3()
{
char[] chars = new char[] { 'a', 'b' };
object obj = new object();
IWorkItemResult<char> wir = _stp.QueueWorkItem(new Func<bool, char[], object, char>(Func3), true, chars, obj);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 3);
Assert.AreEqual(args[0], true);
Assert.AreEqual(args[1], chars);
Assert.AreEqual(args[2], obj);
}
[Test]
public void FuncT4()
{
IntPtr p = new IntPtr(int.MaxValue);
Guid guid = Guid.NewGuid();
IPAddress ip = IPAddress.Parse("1.2.3.4");
IWorkItemResult<IPAddress> wir = _stp.QueueWorkItem(new Func<long, IntPtr, IPAddress, Guid, IPAddress>(Func4), long.MinValue, p, ip, guid);
object[] args = wir.State as object[];
Assert.IsNotNull(args);
Assert.AreEqual(args.Length, 4);
Assert.AreEqual(args[0], long.MinValue);
Assert.AreEqual(args[1], p);
Assert.AreEqual(args[2], ip);
Assert.AreEqual(args[3], guid);
}
private void Action0()
{
}
private void Action1(int p1)
{
}
private void Action2(char p1, string p2)
{
}
private void Action3(bool p1, char [] p2, object p3)
{
}
private void Action4(long p1, IntPtr p2, IPAddress p3, Guid p4)
{
}
private int Func0()
{
return 0;
}
private bool Func1(int p1)
{
return true;
}
private string Func2(char p1, string p2)
{
return "value";
}
private char Func3(bool p1, char[] p2, object p3)
{
return 'z';
}
private IPAddress Func4(long p1, IntPtr p2, IPAddress p3, Guid p4)
{
return IPAddress.None;
}
}
}
+107
View File
@@ -0,0 +1,107 @@
using Amib.Threading;
using NUnit.Framework;
namespace WorkItemsGroupTests
{
[TestFixture]
[Category("TestWIGFuncT")]
public class TestWIGFuncT
{
private SmartThreadPool _stp;
private IWorkItemsGroup _wig;
[SetUp]
public void Init()
{
_stp = new SmartThreadPool();
_wig = _stp.CreateWorkItemsGroup(10);
}
[TearDown]
public void Fini()
{
_stp.Shutdown();
}
[Test]
public void FuncT0()
{
IWorkItemResult<int> wir = _wig.QueueWorkItem(new Func<int>(MaxInt));
int result = wir.GetResult();
Assert.AreEqual(result, int.MaxValue);
}
[Test]
public void FuncT1()
{
IWorkItemResult<bool> wir = _wig.QueueWorkItem(new Func<bool, bool>(Not), true);
bool result = wir.Result;
Assert.AreEqual(result, false);
}
[Test]
public void FuncT2()
{
IWorkItemResult<string> wir = _wig.QueueWorkItem(new Func<string, string, string>(string.Concat), "ABC", "xyz");
string result = wir.Result;
Assert.AreEqual(result, "ABCxyz");
}
[Test]
public void FuncT3()
{
IWorkItemResult<string> wir = _wig.QueueWorkItem(new Func<string, int, int, string>(Substring), "ABCDEF", 1, 2);
string result = wir.Result;
Assert.AreEqual(result, "BC");
}
[Test]
public void FuncT4()
{
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IWorkItemResult<int[]> wir = _wig.QueueWorkItem(new Func<int[], int, int, int, int[]>(Subarray), numbers, 1, 2, 3);
int[] result = wir.Result;
Assert.AreEqual(result, new int[] { 2, 3, 2, 3, 2, 3, });
}
private int MaxInt()
{
return int.MaxValue;
}
private bool Not(bool flag)
{
return !flag;
}
private string Substring(string s, int startIndex, int length)
{
return s.Substring(startIndex, length);
}
private int[] Subarray(int[] numbers, int startIndex, int length, int repeat)
{
int[] result = new int[length * repeat];
for (int i = 0; i < repeat; i++)
{
for (int j = 0; j < length; j++)
{
result[i * length + j] = numbers[startIndex + j];
}
}
return result;
}
}
}
-47
View File
@@ -67,53 +67,6 @@ namespace WorkItemsGroupTests
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>
+104
View File
@@ -0,0 +1,104 @@
using System;
using System.Threading;
using NUnit.Framework;
using Amib.Threading;
using SmartThreadPoolTests;
namespace WorkItemsGroupTests
{
/// <summary>
/// Tests for QueueWorkItem.
/// </summary>
[TestFixture]
[Category("TestQueueWorkItem")]
public class TestQueueWorkItem
{
private SmartThreadPool _stp;
private IWorkItemsGroup _wig;
[SetUp]
public void Init()
{
_stp = new SmartThreadPool();
_wig = _stp.CreateWorkItemsGroup(SmartThreadPool.DefaultMaxWorkerThreads);
}
[TearDown]
public void Fini()
{
_stp.Shutdown();
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback);
[Test]
public void TestQueueWorkItemCall()
{
QueueWorkItemHelper.TestQueueWorkItemCall(_wig);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
[Test]
public void TestQueueWorkItemCallPrio()
{
QueueWorkItemHelper.TestQueueWorkItemCallPrio(_wig);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
[Test]
public void TestQueueWorkItemCallStat()
{
QueueWorkItemHelper.TestQueueWorkItemCallStat(_wig);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
[Test]
public void TestQueueWorkItemCallStatPrio()
{
QueueWorkItemHelper.TestQueueWorkItemCallStatPrio(_wig);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
[Test]
public void TestQueueWorkItemCallStatPost()
{
QueueWorkItemHelper.TestQueueWorkItemCallStatPost(_wig);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
[Test]
public void TestQueueWorkItemCallStatPostPrio()
{
QueueWorkItemHelper.TestQueueWorkItemCallStatPostPrio(_wig);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
[Test]
public void TestQueueWorkItemCallStatPostPflg()
{
QueueWorkItemHelper.TestQueueWorkItemCallStatPostPflg(_wig);
}
//IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
[Test]
public void TestQueueWorkItemCallStatPostPflgPrio()
{
QueueWorkItemHelper.TestQueueWorkItemCallStatPostPflgPrio(_wig);
}
//IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
[Test]
public void TestQueueWorkItemInfoCall()
{
QueueWorkItemHelper.TestQueueWorkItemInfoCall(_wig);
}
//IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
[Test]
public void TestQueueWorkItemInfoCallStat()
{
QueueWorkItemHelper.TestQueueWorkItemInfoCallStat(_wig);
}
}
}
+66 -12
View File
@@ -29,15 +29,17 @@ namespace WorkItemsGroupTests
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(int.MaxValue);
bool success = false;
ManualResetEvent isRunning = new ManualResetEvent(false);
for(int i = 0; i < 100; ++i)
for (int i = 0; i < 4; ++i)
{
workItemsGroup.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
workItemsGroup.QueueWorkItem(delegate { isRunning.WaitOne(); });
}
success = !workItemsGroup.WaitForIdle(3500);
success = !workItemsGroup.WaitForIdle(1000);
isRunning.Set();
success = success && workItemsGroup.WaitForIdle(1000);
smartThreadPool.Shutdown();
@@ -61,7 +63,7 @@ namespace WorkItemsGroupTests
smartThreadPool.Shutdown();
Assert.IsNotNull(e);
}
}
[Test]
public void WaitForIdleOnSTPThreadForAnotherWorkItemsGroup()
@@ -72,11 +74,11 @@ namespace WorkItemsGroupTests
workItemsGroup1.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
1000);
workItemsGroup1.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
1000);
IWorkItemResult wir = workItemsGroup2.QueueWorkItem(
new WorkItemCallback(this.DoWaitForIdle),
@@ -91,11 +93,16 @@ namespace WorkItemsGroupTests
}
private int x = 0;
private int _x = 0;
private object DoSomeWork(object state)
{
Debug.WriteLine(Interlocked.Increment(ref x));
Thread.Sleep(1000);
{
int sleepTime = (int)state;
int newX = Interlocked.Increment(ref _x);
Console.WriteLine("{0}: Enter, newX = {1}", DateTime.Now.ToLongTimeString(), newX);
Console.WriteLine("{0}: Sleeping for {1} ms", DateTime.Now.ToLongTimeString(), sleepTime);
Thread.Sleep(sleepTime);
newX = Interlocked.Increment(ref _x);
Console.WriteLine("{0}: Leave, newX = {1}", DateTime.Now.ToLongTimeString(), newX);
return 1;
}
@@ -105,5 +112,52 @@ namespace WorkItemsGroupTests
workItemsGroup.WaitForIdle();
return null;
}
[Test]
public void WaitForIdleWithCancel()
{
SmartThreadPool smartThreadPool = new SmartThreadPool(10 * 1000, 1, 1);
IWorkItemsGroup workItemsGroup = smartThreadPool.CreateWorkItemsGroup(2);
_x = 0;
IWorkItemResult wir1 = workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), 1000);
IWorkItemResult wir2 = workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), 1000);
IWorkItemResult wir3 = workItemsGroup.QueueWorkItem(new WorkItemCallback(this.DoSomeWork), 1000);
while (0 == _x)
{
Thread.Sleep(10);
}
Console.WriteLine("{0}: Cancelling WIG", DateTime.Now.ToLongTimeString());
workItemsGroup.Cancel();
// At this point:
// The first work item is running
// The second work item is cancelled, but waits in the STP queue
// The third work item is cancelled.
Assert.AreEqual(1, _x);
Assert.IsTrue(wir2.IsCanceled);
Assert.IsTrue(wir3.IsCanceled);
// Make sure the workItemsGroup is still idle
Assert.IsFalse(workItemsGroup.IsIdle);
Console.WriteLine("{0}: Waiting for 1st result", DateTime.Now.ToLongTimeString());
wir1.GetResult();
Assert.AreEqual(2, _x);
bool isIdle = workItemsGroup.WaitForIdle(100);
Assert.IsTrue(isIdle);
smartThreadPool.Shutdown();
}
}
}
+7 -5
View File
@@ -28,15 +28,17 @@ namespace SmartThreadPoolTests
SmartThreadPool smartThreadPool = new SmartThreadPool(10*1000, 25, 0);
bool success = false;
ManualResetEvent isRunning = new ManualResetEvent(false);
for(int i = 0; i < 100; ++i)
for(int i = 0; i < 4; ++i)
{
smartThreadPool.QueueWorkItem(
new WorkItemCallback(this.DoSomeWork),
null);
smartThreadPool.QueueWorkItem(delegate { isRunning.WaitOne(); });
}
success = !smartThreadPool.WaitForIdle(3500);
success = !smartThreadPool.WaitForIdle(1000);
isRunning.Set();
success = success && smartThreadPool.WaitForIdle(1000);
smartThreadPool.Shutdown();
-47
View File
@@ -70,53 +70,6 @@ namespace WorkItemsGroupTests
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>
+71 -17
View File
@@ -1,14 +1,53 @@
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}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartThreadPoolCE", "SmartThreadPool\SmartThreadPoolCE.csproj", "{D81DD596-C71F-4AC2-816C-63C19589E7E0}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartThreadPool", "SmartThreadPool\SmartThreadPool.csproj", "{74D4C33F-7CC8-4B2A-A7DF-D8B6E63B6EBD}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STPExamples", "STPExamples\STPExamples.csproj", "{AE943A5A-7CFD-4E0D-BA51-FB763AAEA9A3}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
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}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestSmartThreadPool", "TestSmartThreadPool\TestSmartThreadPool.csproj", "{976DB12F-9198-4AD9-981A-1652615C9B0D}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UsageControl", "UsageControl\UsageControl.csproj", "{C11A4561-CCB5-4C96-8DF2-B804031D89D8}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkItemsGroupDemo", "WorkItemsGroupDemo\WorkItemsGroupDemo.csproj", "{DC005A64-FAE9-4CFA-ADC8-F1D1FE7FE6CD}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STPCEDemo", "STPCEDemo\STPCEDemo.csproj", "{356114BA-5F10-4DB6-9971-987CE11F765F}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -16,26 +55,41 @@ Global
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
{D81DD596-C71F-4AC2-816C-63C19589E7E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D81DD596-C71F-4AC2-816C-63C19589E7E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D81DD596-C71F-4AC2-816C-63C19589E7E0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{D81DD596-C71F-4AC2-816C-63C19589E7E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D81DD596-C71F-4AC2-816C-63C19589E7E0}.Release|Any CPU.Build.0 = Release|Any CPU
{74D4C33F-7CC8-4B2A-A7DF-D8B6E63B6EBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{74D4C33F-7CC8-4B2A-A7DF-D8B6E63B6EBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74D4C33F-7CC8-4B2A-A7DF-D8B6E63B6EBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{74D4C33F-7CC8-4B2A-A7DF-D8B6E63B6EBD}.Release|Any CPU.Build.0 = Release|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
{AE943A5A-7CFD-4E0D-BA51-FB763AAEA9A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE943A5A-7CFD-4E0D-BA51-FB763AAEA9A3}.Release|Any CPU.Build.0 = Release|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
{6A3E4DBF-12AD-4636-ACB3-24B5172FAE03}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A3E4DBF-12AD-4636-ACB3-24B5172FAE03}.Release|Any CPU.Build.0 = Release|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
{976DB12F-9198-4AD9-981A-1652615C9B0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{976DB12F-9198-4AD9-981A-1652615C9B0D}.Release|Any CPU.Build.0 = Release|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 = Release|Any CPU
{C11A4561-CCB5-4C96-8DF2-B804031D89D8}.Release|Any CPU.Build.0 = Release|Any CPU
{DC005A64-FAE9-4CFA-ADC8-F1D1FE7FE6CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC005A64-FAE9-4CFA-ADC8-F1D1FE7FE6CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC005A64-FAE9-4CFA-ADC8-F1D1FE7FE6CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC005A64-FAE9-4CFA-ADC8-F1D1FE7FE6CD}.Release|Any CPU.Build.0 = Release|Any CPU
{356114BA-5F10-4DB6-9971-987CE11F765F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{356114BA-5F10-4DB6-9971-987CE11F765F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{356114BA-5F10-4DB6-9971-987CE11F765F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{356114BA-5F10-4DB6-9971-987CE11F765F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{356114BA-5F10-4DB6-9971-987CE11F765F}.Release|Any CPU.Build.0 = Release|Any CPU
{356114BA-5F10-4DB6-9971-987CE11F765F}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
-61
View File
@@ -1,61 +0,0 @@
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("")]
+21 -15
View File
@@ -1,3 +1,6 @@
#if !(WindowsCE)
using System;
using System.Diagnostics;
using System.Threading;
@@ -6,7 +9,7 @@ using System.Web;
using System.Runtime.Remoting.Messaging;
namespace Amib.Threading
namespace Amib.Threading.Internal
{
#region CallerThreadContext class
@@ -19,10 +22,10 @@ namespace Amib.Threading
#region Prepare reflection information
// Cached type information.
private static MethodInfo getLogicalCallContextMethodInfo =
private static readonly MethodInfo getLogicalCallContextMethodInfo =
typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
private static MethodInfo setLogicalCallContextMethodInfo =
private static readonly MethodInfo setLogicalCallContextMethodInfo =
typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
private static string HttpContextSlotName = GetHttpContextSlotName();
@@ -31,18 +34,20 @@ namespace Amib.Threading
{
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";
if (fi != null)
{
return (string) fi.GetValue(null);
}
return "HttpContext";
}
#endregion
#region Private fields
private HttpContext _httpContext = null;
private LogicalCallContext _callContext = null;
private HttpContext _httpContext;
private LogicalCallContext _callContext;
#endregion
@@ -118,15 +123,16 @@ namespace Amib.Threading
{
setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
}
// Restore HttpContext
if (callerThreadContext._httpContext != null)
{
// Restore HttpContext
if (callerThreadContext._httpContext != null)
{
HttpContext.Current = callerThreadContext._httpContext;
}
//CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
}
}
}
#endregion
}
#endif
+99
View File
@@ -0,0 +1,99 @@
#if (WindowsCE)
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace Amib.Threading.Internal
{
/// <summary>
/// EventWaitHandle class
/// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation.
/// So I wrote this class to implement these two methods with some of their overloads.
/// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny.
/// Note that this class doesn't even inherit from WaitHandle!
/// </summary>
public class EventWaitHandle
{
#region Public Constants
public const int WaitTimeout = Timeout.Infinite;
#endregion
#region Private External Constants
private const Int32 WAIT_FAILED = -1;
private const Int32 WAIT_TIMEOUT = 0x102;
private const UInt32 INFINITE = 0xFFFFFFFF;
#endregion
#region WaitAll and WaitAny
private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles)
{
IntPtr[] nativeHandles = new IntPtr[waitHandles.Length];
for (int i = 0; i < waitHandles.Length; i++)
{
nativeHandles[i] = waitHandles[i].Handle;
}
return nativeHandles;
}
public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
{
uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout);
if (result == WAIT_TIMEOUT || result == WAIT_FAILED)
{
return false;
}
return true;
}
public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
{
uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout;
IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles);
int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout);
if (result >= 0 && result < waitHandles.Length)
{
return result;
}
return -1;
}
public static int WaitAny(WaitHandle[] waitHandles)
{
return WaitAny(waitHandles, Timeout.Infinite, false);
}
public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext)
{
int millisecondsTimeout = (int)timeout.TotalMilliseconds;
return WaitAny(waitHandles, millisecondsTimeout, false);
}
#endregion
#region External methods
[DllImport("coredll.dll", SetLastError = true)]
public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds);
#endregion
}
}
#endif
+82
View File
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace Amib.Threading.Internal
{
/// <summary>
/// EventWaitHandleFactory class.
/// This is a static class that creates AutoResetEvent and ManualResetEvent objects.
/// In WindowCE the WaitForMultipleObjects API fails to use the Handle property
/// of XxxResetEvent. It can use only handles that were created by the CreateEvent API.
/// Consequently this class creates the needed XxxResetEvent and replaces the handle if
/// it's a WindowsCE OS.
/// </summary>
public static class EventWaitHandleFactory
{
/// <summary>
/// Create a new AutoResetEvent object
/// </summary>
/// <returns>Return a new AutoResetEvent object</returns>
public static AutoResetEvent CreateAutoResetEvent()
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
#if (WindowsCE)
ReplaceEventHandle(waitHandle, false, false);
#endif
return waitHandle;
}
/// <summary>
/// Create a new ManualResetEvent object
/// </summary>
/// <returns>Return a new ManualResetEvent object</returns>
public static ManualResetEvent CreateManualResetEvent(bool initialState)
{
ManualResetEvent waitHandle = new ManualResetEvent(initialState);
#if (WindowsCE)
ReplaceEventHandle(waitHandle, true, initialState);
#endif
return waitHandle;
}
#if (WindowsCE)
/// <summary>
/// Replace the event handle
/// </summary>
/// <param name="waitHandle">The WaitHandle object which its handle needs to be replaced.</param>
/// <param name="manualReset">Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false)</param>
/// <param name="initialState">The initial state of the event</param>
private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState)
{
// Store the old handle
IntPtr oldHandle = waitHandle.Handle;
// Create a new event
IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null);
// Replace the old event with the new event
waitHandle.Handle = newHandle;
// Close the old event
CloseHandle (oldHandle);
}
[DllImport("coredll.dll", SetLastError = true)]
public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
//Handle
[DllImport("coredll.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
#endif
}
}
+89 -59
View File
@@ -1,81 +1,111 @@
// Ami Bar
// amibar@gmail.com
using System;
#if !(WindowsCE)
using System.Runtime.Serialization;
#endif
namespace Amib.Threading
{
#region Exceptions
#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
/// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
/// </summary>
public sealed partial class WorkItemCancelException : ApplicationException
{
public WorkItemTimeoutException() : base()
public WorkItemCancelException()
{
}
public WorkItemTimeoutException(string message) : base(message)
public WorkItemCancelException(string message)
: base(message)
{
}
public WorkItemTimeoutException(string message, Exception e) : base(message, e)
{
}
public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) : base(si, sc)
public WorkItemCancelException(string message, Exception e)
: base(message, e)
{
}
}
/// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
/// </summary>
[Serializable]
public sealed class WorkItemResultException : ApplicationException
{
public WorkItemResultException() : base()
{
}
/// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
/// </summary>
public sealed partial class WorkItemTimeoutException : ApplicationException
{
public WorkItemTimeoutException()
{
}
public WorkItemResultException(string message) : base(message)
{
}
public WorkItemTimeoutException(string message)
: base(message)
{
}
public WorkItemResultException(string message, Exception e) : base(message, e)
{
}
public WorkItemTimeoutException(string message, Exception e)
: base(message, e)
{
}
}
public WorkItemResultException(SerializationInfo si, StreamingContext sc) : base(si, sc)
{
}
}
/// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been timed out
/// </summary>
public sealed partial class WorkItemResultException : ApplicationException
{
public WorkItemResultException()
{
}
#endregion
public WorkItemResultException(string message)
: base(message)
{
}
public WorkItemResultException(string message, Exception e)
: base(message, e)
{
}
}
#if !(WindowsCE)
/// <summary>
/// Represents an exception in case IWorkItemResult.GetResult has been canceled
/// </summary>
[Serializable]
public sealed partial class WorkItemCancelException
{
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 partial class WorkItemTimeoutException
{
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 partial class WorkItemResultException
{
public WorkItemResultException(SerializationInfo si, StreamingContext sc)
: base(si, sc)
{
}
}
#endif
#endregion
}
+375 -46
View File
@@ -1,6 +1,3 @@
// Ami Bar
// amibar@gmail.com
using System;
using System.Threading;
@@ -18,7 +15,13 @@ namespace Amib.Threading
/// A delegate to call after the WorkItemCallback completed
/// </summary>
/// <param name="wir">The work item result object</param>
public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
/// <summary>
/// A delegate to call after the WorkItemCallback completed
/// </summary>
/// <param name="wir">The work item result object</param>
public delegate void PostExecuteWorkItemCallback<TResult>(IWorkItemResult<TResult> wir);
/// <summary>
/// A delegate to call when a WorkItemsGroup becomes idle
@@ -26,10 +29,27 @@ namespace Amib.Threading
/// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param>
public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
/// <summary>
/// A delegate to call after a thread is created, but before
/// it's first use.
/// </summary>
public delegate void ThreadInitializationHandler();
/// <summary>
/// A delegate to call when a thread is about to exit, after
/// it is no longer belong to the pool.
/// </summary>
public delegate void ThreadTerminationHandler();
#endregion
#region WorkItem Priority
/// <summary>
/// Defines the availeable priorities of a work item.
/// The higher the priority a work item has, the sooner
/// it will be executed.
/// </summary>
public enum WorkItemPriority
{
Lowest,
@@ -41,19 +61,11 @@ namespace Amib.Threading
#endregion
#region IHasWorkItemPriority interface
public interface IHasWorkItemPriority
{
WorkItemPriority WorkItemPriority { get; }
}
#endregion
#region IWorkItemsGroup interface
/// <summary>
/// IWorkItemsGroup interface
/// Created by SmartThreadPool.CreateWorkItemsGroup()
/// </summary>
public interface IWorkItemsGroup
{
@@ -62,28 +74,264 @@ namespace Amib.Threading
/// </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);
/// <summary>
/// Get/Set the maximum number of workitem that execute cocurrency on the thread pool
/// </summary>
int Concurrency { get; set; }
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
/// <summary>
/// Get the number of work items waiting in the queue.
/// </summary>
int WaitingCallbacks { get; }
/// <summary>
/// Get an array with all the state objects of the currently running items.
/// The array represents a snap shot and impact performance.
/// </summary>
object[] GetStates();
/// <summary>
/// Get the WorkItemsGroup start information
/// </summary>
WIGStartInfo WIGStartInfo { get; }
/// <summary>
/// Starts to execute work items
/// </summary>
void Start();
/// <summary>
/// Cancel all the work items.
/// Same as Cancel(false)
/// </summary>
void Cancel();
/// <summary>
/// Cancel all work items using thread abortion
/// </summary>
/// <param name="abortExecution">True to stop work items by raising ThreadAbortException</param>
void Cancel(bool abortExecution);
/// <summary>
/// Wait for all work item to complete.
/// </summary>
void WaitForIdle();
/// <summary>
/// Wait for all work item to complete, until timeout expired
/// </summary>
/// <param name="timeout">How long to wait for the work items to complete</param>
/// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
bool WaitForIdle(TimeSpan timeout);
bool WaitForIdle(int millisecondsTimeout);
int WaitingCallbacks { get; }
event WorkItemsGroupIdleHandler OnIdle;
/// <summary>
/// Wait for all work item to complete, until timeout expired
/// </summary>
/// <param name="millisecondsTimeout">How long to wait for the work items to complete in milliseconds</param>
/// <returns>Returns true if work items completed within the timeout, otherwise false.</returns>
bool WaitForIdle(int millisecondsTimeout);
void Cancel();
void Start();
}
/// <summary>
/// IsIdle is true when there are no work items running or queued.
/// </summary>
bool IsIdle { get; }
/// <summary>
/// This event is fired when all work items are completed.
/// (When IsIdle changes to true)
/// This event only work on WorkItemsGroup. On SmartThreadPool
/// it throws the NotImplementedException.
/// </summary>
event WorkItemsGroupIdleHandler OnIdle;
#region QueueWorkItem
/// <summary>
/// Queue a work item
/// </summary>
/// <param name="callback">A callback to execute</param>
/// <returns>Returns a work item result</returns>
IWorkItemResult QueueWorkItem(WorkItemCallback callback);
/// <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>
IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
/// <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>
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
/// <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>
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
/// <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>
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
/// <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>
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
/// <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>
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
/// <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>
IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
/// <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>
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
/// <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>
IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
#endregion
#region QueueWorkItem(Action<...>)
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem(Action action);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T>(Action<T> action, T arg);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult object, but its GetResult() will always return null</returns>
IWorkItemResult QueueWorkItem<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
#endregion
#region QueueWorkItem(Func<...>)
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult<TResult> object.
/// its GetResult() returns a TResult object</returns>
IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult<TResult> object.
/// its GetResult() returns a TResult object</returns>
IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult<TResult> object.
/// its GetResult() returns a TResult object</returns>
IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult<TResult> object.
/// its GetResult() returns a TResult object</returns>
IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3);
/// <summary>
/// Queue a work item.
/// </summary>
/// <returns>Returns a IWorkItemResult<TResult> object.
/// its GetResult() returns a TResult object</returns>
IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
#endregion
}
#endregion
@@ -92,9 +340,24 @@ namespace Amib.Threading
[Flags]
public enum CallToPostExecute
{
/// <summary>
/// Never call to the PostExecute call back
/// </summary>
Never = 0x00,
/// <summary>
/// Call to the PostExecute only when the work item is cancelled
/// </summary>
WhenWorkItemCanceled = 0x01,
/// <summary>
/// Call to the PostExecute only when the work item is not cancelled
/// </summary>
WhenWorkItemNotCanceled = 0x02,
/// <summary>
/// Always call to the PostExecute
/// </summary>
Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
}
@@ -102,17 +365,44 @@ namespace Amib.Threading
#region IWorkItemResult interface
/// <summary>
/// The common interface of IWorkItemResult and IWorkItemResult<T>
/// </summary>
public interface IWaitableResult
{
/// <summary>
/// This method intent is for internal use.
/// </summary>
/// <returns></returns>
IWorkItemResult GetWorkItemResult();
/// <summary>
/// This method intent is for internal use.
/// </summary>
/// <returns></returns>
IWorkItemResult<TResult> GetWorkItemResultT<TResult>();
}
/// <summary>
/// IWorkItemResult interface.
/// Created when a WorkItemCallback work item is queued.
/// </summary>
public interface IWorkItemResult : IWorkItemResult<object>
{
}
/// <summary>
/// IWorkItemResult interface
/// IWorkItemResult<TResult> interface.
/// Created when a Func<T> work item is queued.
/// </summary>
public interface IWorkItemResult
public interface IWorkItemResult<TResult> : IWaitableResult
{
/// <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();
TResult GetResult();
/// <summary>
/// Get the result of the work item.
@@ -120,7 +410,7 @@ namespace Amib.Threading
/// </summary>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
object GetResult(
TResult GetResult(
int millisecondsTimeout,
bool exitContext);
@@ -130,7 +420,7 @@ namespace Amib.Threading
/// </summary>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
object GetResult(
TResult GetResult(
TimeSpan timeout,
bool exitContext);
@@ -146,7 +436,7 @@ namespace Amib.Threading
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
object GetResult(
TResult GetResult(
int millisecondsTimeout,
bool exitContext,
WaitHandle cancelWaitHandle);
@@ -158,7 +448,7 @@ namespace Amib.Threading
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
object GetResult(
TResult GetResult(
TimeSpan timeout,
bool exitContext,
WaitHandle cancelWaitHandle);
@@ -169,16 +459,18 @@ namespace Amib.Threading
/// </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);
TResult 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="millisecondsTimeout"></param>
/// <param name="exitContext"></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
object GetResult(
TResult GetResult(
int millisecondsTimeout,
bool exitContext,
out Exception e);
@@ -187,10 +479,12 @@ namespace Amib.Threading
/// Get the result of the work item.
/// If the work item didn't run yet then the caller waits until timeout.
/// </summary>
/// <param name="exitContext"></param>
/// <param name="e">Filled with the exception if one was thrown</param>
/// <param name="timeout"></param>
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
object GetResult(
TResult GetResult(
TimeSpan timeout,
bool exitContext,
out Exception e);
@@ -208,7 +502,7 @@ namespace Amib.Threading
/// <returns>The result of the work item</returns>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
object GetResult(
TResult GetResult(
int millisecondsTimeout,
bool exitContext,
WaitHandle cancelWaitHandle,
@@ -219,10 +513,13 @@ namespace Amib.Threading
/// 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="cancelWaitHandle"></param>
/// <param name="e">Filled with the exception if one was thrown</param>
/// <param name="timeout"></param>
/// <param name="exitContext"></param>
/// On timeout throws WorkItemTimeoutException
/// On cancel throws WorkItemCancelException
object GetResult(
TResult GetResult(
TimeSpan timeout,
bool exitContext,
WaitHandle cancelWaitHandle,
@@ -239,15 +536,29 @@ namespace Amib.Threading
bool IsCanceled { get; }
/// <summary>
/// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
/// Gets the user-defined object that contains context data
/// for the work item method.
/// </summary>
object State { get; }
/// <summary>
/// Cancel the work item if it didn't start running yet.
/// Same as Cancel(false).
/// </summary>
/// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
bool Cancel();
bool Cancel();
/// <summary>
/// Cancel the work item execution.
/// If the work item is in the queue then it won't execute
/// If the work item is completed, it will remain completed
/// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled
/// property to check if the work item has been cancelled. If the abortExecution is set to true then
/// the Smart Thread Pool will send an AbortException to the running thread to stop the execution
/// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException.
/// If the work item is already cancelled it will remain cancelled
/// </summary>
/// <param name="abortExecution">When true send an AbortException to the executing thread.</param>
/// <returns>Returns true if the work item was not completed, otherwise false.</returns>
bool Cancel(bool abortExecution);
/// <summary>
/// Get the work item's priority
@@ -257,7 +568,7 @@ namespace Amib.Threading
/// <summary>
/// Return the result, same as GetResult()
/// </summary>
object Result { get; }
TResult Result { get; }
/// <summary>
/// Returns the exception if occured otherwise returns null.
@@ -266,4 +577,22 @@ namespace Amib.Threading
}
#endregion
#region .NET 3.5
// All these delegate are built-in .NET 3.5
// Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity.
public delegate void Action();
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
public delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
public delegate TResult Func<TResult>();
public delegate TResult Func<T, TResult>(T arg1);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);
public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
#endregion
}
+4 -7
View File
@@ -1,6 +1,3 @@
// Ami Bar
// amibar@gmail.com
using System;
using System.Collections;
using System.Diagnostics;
@@ -25,17 +22,17 @@ namespace Amib.Threading.Internal
/// <summary>
/// Work items queues. There is one for each type of priority
/// </summary>
private Queue [] _queues = new Queue[_queuesCount];
private readonly Queue [] _queues = new Queue[_queuesCount];
/// <summary>
/// The total number of work items within the queues
/// </summary>
private int _workItemsCount = 0;
private int _workItemsCount;
/// <summary>
/// Use with IEnumerable interface
/// </summary>
private int _version = 0;
private int _version;
#endregion
@@ -159,7 +156,7 @@ namespace Amib.Threading.Internal
/// </summary>
private class PriorityQueueEnumerator : IEnumerator
{
private PriorityQueue _priorityQueue;
private readonly PriorityQueue _priorityQueue;
private int _version;
private int _queueIndex;
private IEnumerator _enumerator;
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.CompilerServices;
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("Amib.Threading")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Amib.Threading")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c764a3de-c4f8-434d-85b5-a09830d1e44f")]
// 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("2.0.0.0")]
+61 -44
View File
@@ -3,7 +3,17 @@ using System.Diagnostics;
namespace Amib.Threading.Internal
{
internal enum STPPerformanceCounterType
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);
}
#if !(WindowsCE)
internal enum STPPerformanceCounterType
{
// Fields
ActiveThreads = 0,
@@ -37,7 +47,7 @@ namespace Amib.Threading.Internal
internal class STPPerformanceCounter
{
// Fields
private PerformanceCounterType _pcType;
private readonly PerformanceCounterType _pcType;
protected string _counterHelp;
protected string _counterName;
@@ -47,9 +57,9 @@ namespace Amib.Threading.Internal
string counterHelp,
PerformanceCounterType pcType)
{
this._counterName = counterName;
this._counterHelp = counterHelp;
this._pcType = pcType;
_counterName = counterName;
_counterHelp = counterHelp;
_pcType = pcType;
}
public void AddCounterToCollection(CounterCreationDataCollection counterData)
@@ -76,7 +86,7 @@ namespace Amib.Threading.Internal
{
// Fields
internal STPPerformanceCounter[] _stpPerformanceCounters;
private static STPPerformanceCounters _instance;
private static readonly STPPerformanceCounters _instance;
internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
internal const string _stpCategoryName = "SmartThreadPool";
@@ -149,16 +159,18 @@ namespace Amib.Threading.Internal
internal class STPInstancePerformanceCounter : IDisposable
{
// Fields
private bool _isDisposed;
private PerformanceCounter _pcs;
// Methods
protected STPInstancePerformanceCounter()
{
_isDisposed = false;
}
public STPInstancePerformanceCounter(
string instance,
STPPerformanceCounterType spcType)
STPPerformanceCounterType spcType) : this()
{
STPPerformanceCounters counters = STPPerformanceCounters.Instance;
_pcs = new PerformanceCounter(
@@ -169,10 +181,6 @@ namespace Amib.Threading.Internal
_pcs.RawValue = _pcs.RawValue;
}
~STPInstancePerformanceCounter()
{
Close();
}
public void Close()
{
@@ -186,9 +194,20 @@ namespace Amib.Threading.Internal
public void Dispose()
{
Close();
GC.SuppressFinalize(this);
Dispose(true);
}
public virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
Close();
}
}
_isDisposed = true;
}
public virtual void Increment()
{
@@ -209,27 +228,19 @@ namespace Amib.Threading.Internal
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
internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters
{
private bool _isDisposed;
// Fields
private STPInstancePerformanceCounter[] _pcs;
private static STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
// Methods
static STPInstancePerformanceCounters()
@@ -239,8 +250,13 @@ namespace Amib.Threading.Internal
public STPInstancePerformanceCounters(string instance)
{
_isDisposed = false;
_pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
STPPerformanceCounters counters = STPPerformanceCounters.Instance;
// Call the STPPerformanceCounters.Instance so the static constructor will
// intialize the STPPerformanceCounters singleton.
STPPerformanceCounters.Instance.GetHashCode();
for (int i = 0; i < _pcs.Length; i++)
{
if (instance != null)
@@ -265,23 +281,29 @@ namespace Amib.Threading.Internal
{
if (null != _pcs[i])
{
_pcs[i].Close();
_pcs[i].Dispose();
}
}
_pcs = null;
}
}
~STPInstancePerformanceCounters()
{
Close();
}
public void Dispose()
{
Close();
GC.SuppressFinalize(this);
Dispose(true);
}
public virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
Close();
}
}
_isDisposed = true;
}
private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
{
@@ -319,22 +341,18 @@ namespace Amib.Threading.Internal
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds);
GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
}
}
}
#endif
internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable
internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters
{
static NullSTPInstancePerformanceCounters()
{
}
private static NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(null);
private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters();
public static NullSTPInstancePerformanceCounters Instance
{
get { return _instance; }
}
public NullSTPInstancePerformanceCounters(string instance) {}
public void Close() {}
public void Dispose() {}
@@ -342,6 +360,5 @@ namespace Amib.Threading.Internal
public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {}
}
}
}
+194 -58
View File
@@ -1,6 +1,4 @@
// Ami Bar
// amibar@gmail.com
using System;
using System.Threading;
namespace Amib.Threading
@@ -8,82 +6,220 @@ 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;
public class STPStartInfo : WIGStartInfo
{
private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority;
private string _pcInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
/// <summary>
/// The lower limit of threads in the pool.
/// </summary>
private int _minWorkerThreads;
public STPStartInfo()
{
}
/// <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)
public STPStartInfo(STPStartInfo stpStartInfo)
: base(stpStartInfo)
{
_idleTimeout = stpStartInfo._idleTimeout;
_minWorkerThreads = stpStartInfo._minWorkerThreads;
_maxWorkerThreads = stpStartInfo._maxWorkerThreads;
_threadPriority = stpStartInfo._threadPriority;
_pcInstanceName = stpStartInfo._pcInstanceName;
}
_threadPriority = stpStartInfo._threadPriority;
_pcInstanceName = stpStartInfo._pcInstanceName;
}
public int IdleTimeout
/// <summary>
/// Get/Set the idle timeout in milliseconds.
/// If a thread is idle (starved) longer than IdleTimeout then it may quit.
/// </summary>
public virtual int IdleTimeout
{
get { return _idleTimeout; }
set { _idleTimeout = value; }
}
public int MinWorkerThreads
/// <summary>
/// Get/Set the lower limit of threads in the pool.
/// </summary>
public virtual int MinWorkerThreads
{
get { return _minWorkerThreads; }
set { _minWorkerThreads = value; }
}
public int MaxWorkerThreads
/// <summary>
/// Get/Set the upper limit of threads in the pool.
/// </summary>
public virtual int MaxWorkerThreads
{
get { return _maxWorkerThreads; }
set { _maxWorkerThreads = value; }
}
public ThreadPriority ThreadPriority
{
get { return _threadPriority; }
set { _threadPriority = value; }
}
/// <summary>
/// Get/Set the scheduling priority of the threads in the pool.
/// The Os handles the scheduling.
/// </summary>
public virtual ThreadPriority ThreadPriority
{
get { return _threadPriority; }
set { _threadPriority = value; }
}
public string PerformanceCounterInstanceName
{
get { return _pcInstanceName; }
set { _pcInstanceName = value; }
}
}
/// <summary>
/// Get/Set the performance counter instance name of this SmartThreadPool
/// The default is null which indicate not to use performance counters at all.
/// </summary>
public virtual string PerformanceCounterInstanceName
{
get { return _pcInstanceName; }
set { _pcInstanceName = value; }
}
/// <summary>
/// Get a readonly version of this STPStartInfo.
/// </summary>
/// <returns>Returns a readonly reference to this STPStartInfo</returns>
public new STPStartInfo AsReadOnly()
{
return new STPStartInfoRO(this);
}
#region STPStartInfoRO class
private class STPStartInfoRO : STPStartInfo
{
private readonly STPStartInfo _stpStartInfo;
public STPStartInfoRO(STPStartInfo stpStartInfo)
{
_stpStartInfo = stpStartInfo;
}
/// <summary>
/// Get/Set the idle timeout in milliseconds.
/// If a thread is idle (starved) longer than IdleTimeout then it may quit.
/// </summary>
public override int IdleTimeout
{
get { return _stpStartInfo.IdleTimeout; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get the lower limit of threads in the pool.
/// </summary>
public override int MinWorkerThreads
{
get { return _stpStartInfo.MinWorkerThreads; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get the upper limit of threads in the pool.
/// </summary>
public override int MaxWorkerThreads
{
get { return _stpStartInfo.MaxWorkerThreads; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get the scheduling priority of the threads in the pool.
/// The Os handles the scheduling.
/// </summary>
public override ThreadPriority ThreadPriority
{
get { return _stpStartInfo.ThreadPriority; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get the performance counter instance name of this SmartThreadPool
/// The default is null which indicate not to use performance counters at all.
/// </summary>
public override string PerformanceCounterInstanceName
{
get { return _stpStartInfo.PerformanceCounterInstanceName; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get if to use the caller's security context
/// </summary>
public override bool UseCallerCallContext
{
get { return _stpStartInfo.UseCallerCallContext; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get if to use the caller's HTTP context
/// </summary>
public override bool UseCallerHttpContext
{
get { return _stpStartInfo.UseCallerHttpContext; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get if to dispose of the state object of a work item
/// </summary>
public override bool DisposeOfStateObjects
{
get { return _stpStartInfo.DisposeOfStateObjects; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get the run the post execute options
/// </summary>
public override CallToPostExecute CallToPostExecute
{
get { return _stpStartInfo.CallToPostExecute; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get the default post execute callback
/// </summary>
public override PostExecuteWorkItemCallback PostExecuteWorkItemCallback
{
get { return _stpStartInfo.PostExecuteWorkItemCallback; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get if the work items execution should be suspended until the Start()
/// method is called.
/// </summary>
public override bool StartSuspended
{
get { return _stpStartInfo.StartSuspended; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get the default priority that a work item gets when it is enqueued
/// </summary>
public override WorkItemPriority WorkItemPriority
{
get { return _stpStartInfo.WorkItemPriority; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Indicate if QueueWorkItem of Action<...>/Func<...> fill the
/// arguments as an object array into the state of the work item.
/// The arguments can be access later by IWorkItemResult.State.
/// </summary>
public override bool FillStateWithArgs
{
get { return _stpStartInfo.FillStateWithArgs; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
}
#endregion
}
}
File diff suppressed because it is too large Load Diff
+52 -123
View File
@@ -1,141 +1,70 @@
<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>
<ProjectGuid>{74D4C33F-7CC8-4B2A-A7DF-D8B6E63B6EBD}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>SmartThreadPool</RootNamespace>
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
<StartupObject>
</StartupObject>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<NoStandardLibraries>false</NoStandardLibraries>
<AssemblyName>SmartThreadPool</AssemblyName>
<RootNamespace>Amib.Threading</RootNamespace>
</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>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>.\bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</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>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<RegisterForComInterop>false</RegisterForComInterop>
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>none</DebugType>
<ErrorReport>prompt</ErrorReport>
<OutputPath>.\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugCE|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\DebugCE\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseCE|AnyCPU' ">
<OutputPath>bin\ReleaseCE\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
</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>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
</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>
<Compile Include="CallerThreadContext.cs" />
<Compile Include="EventWaitHandleFactory.cs" />
<Compile Include="Exceptions.cs" />
<Compile Include="Interfaces.cs" />
<Compile Include="PriorityQueue.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SmartThreadPool.cs" />
<Compile Include="STPPerformanceCounter.cs" />
<Compile Include="STPStartInfo.cs" />
<Compile Include="SynchronizedDictionary.cs" />
<Compile Include="WIGStartInfo.cs" />
<Compile Include="WorkItem.cs" />
<Compile Include="WorkItemFactory.cs" />
<Compile Include="WorkItemInfo.cs" />
<Compile Include="WorkItemResultTWrapper.cs" />
<Compile Include="WorkItemsGroup.cs" />
<Compile Include="WorkItemsGroupBase.cs" />
<Compile Include="WorkItemsQueue.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
<ProjectExtensions>
<VisualStudio AllowExistingFolder="true" />
</ProjectExtensions>
</Project>
+104
View File
@@ -0,0 +1,104 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{D81DD596-C71F-4AC2-816C-63C19589E7E0}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Amib.Threading</RootNamespace>
<AssemblyName>SmartThreadPoolCE</AssemblyName>
<ProjectTypeGuids>{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PlatformFamilyName>WindowsCE</PlatformFamilyName>
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
<OSVersion>5.0</OSVersion>
<DeployDirSuffix>SmartThreadPoolCE</DeployDirSuffix>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FormFactorID>
</FormFactorID>
<SignAssembly>false</SignAssembly>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;$(PlatformFamilyName)</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<FileAlignment>512</FileAlignment>
<WarningLevel>4</WarningLevel>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;$(PlatformFamilyName)</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<FileAlignment>512</FileAlignment>
<WarningLevel>4</WarningLevel>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseCE|AnyCPU' ">
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<OutputPath>bin\ReleaseCE\</OutputPath>
<DefineConstants>TRACE;WindowsCE</DefineConstants>
<Optimize>true</Optimize>
<FileAlignment>512</FileAlignment>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CallerThreadContext.cs" />
<Compile Include="EventWaitHandle.cs" />
<Compile Include="EventWaitHandleFactory.cs" />
<Compile Include="Exceptions.cs" />
<Compile Include="Interfaces.cs" />
<Compile Include="PriorityQueue.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SmartThreadPool.cs" />
<Compile Include="STPPerformanceCounter.cs" />
<Compile Include="STPStartInfo.cs" />
<Compile Include="SynchronizedDictionary.cs" />
<Compile Include="WIGStartInfo.cs" />
<Compile Include="WorkItem.cs" />
<Compile Include="WorkItemFactory.cs" />
<Compile Include="WorkItemInfo.cs" />
<Compile Include="WorkItemResultTWrapper.cs" />
<Compile Include="WorkItemsGroup.cs" />
<Compile Include="WorkItemsGroupBase.cs" />
<Compile Include="WorkItemsQueue.cs" />
</ItemGroup>
<Import Condition="'$(TargetFrameworkVersion)' == 'v1.0'" Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.v1.targets" />
<Import Condition="'$(TargetFrameworkVersion)' == 'v2.0'" Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}">
<HostingProcess disable="1" />
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
+89
View File
@@ -0,0 +1,89 @@
using System.Collections.Generic;
namespace Amib.Threading.Internal
{
internal class SynchronizedDictionary<TKey, TValue>
{
private readonly Dictionary<TKey, TValue> _dictionary;
private readonly object _lock;
public SynchronizedDictionary()
{
_lock = new object();
_dictionary = new Dictionary<TKey, TValue>();
}
public int Count
{
get { return _dictionary.Count; }
}
public bool Contains(TKey key)
{
lock (_lock)
{
return _dictionary.ContainsKey(key);
}
}
public void Remove(TKey key)
{
lock (_lock)
{
_dictionary.Remove(key);
}
}
public object SyncRoot
{
get { return _lock; }
}
public TValue this[TKey key]
{
get
{
lock (_lock)
{
return _dictionary[key];
}
}
set
{
lock (_lock)
{
_dictionary[key] = value;
}
}
}
public Dictionary<TKey, TValue>.KeyCollection Keys
{
get
{
lock (_lock)
{
return _dictionary.Keys;
}
}
}
public Dictionary<TKey, TValue>.ValueCollection Values
{
get
{
lock (_lock)
{
return _dictionary.Values;
}
}
}
public void Clear()
{
lock (_lock)
{
_dictionary.Clear();
}
}
}
}
+169 -58
View File
@@ -1,5 +1,4 @@
// Ami Bar
// amibar@gmail.com
using System;
namespace Amib.Threading
{
@@ -8,92 +7,204 @@ namespace Amib.Threading
/// </summary>
public class WIGStartInfo
{
/// <summary>
/// Use the caller's security context
/// </summary>
private bool _useCallerCallContext;
private bool _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
private bool _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
private bool _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
private CallToPostExecute _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
private PostExecuteWorkItemCallback _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
private WorkItemPriority _workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
private bool _startSuspended = SmartThreadPool.DefaultStartSuspended;
private bool _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs;
/// <summary>
/// Use the caller's HTTP context
/// </summary>
private bool _useCallerHttpContext;
public WIGStartInfo()
{
}
/// <summary>
/// Dispose of the state object of a work item
/// </summary>
private bool _disposeOfStateObjects;
public WIGStartInfo(WIGStartInfo wigStartInfo)
{
_useCallerCallContext = wigStartInfo._useCallerCallContext;
_useCallerHttpContext = wigStartInfo._useCallerHttpContext;
_disposeOfStateObjects = wigStartInfo._disposeOfStateObjects;
_callToPostExecute = wigStartInfo._callToPostExecute;
_postExecuteWorkItemCallback = wigStartInfo._postExecuteWorkItemCallback;
_workItemPriority = wigStartInfo._workItemPriority;
_startSuspended = wigStartInfo._startSuspended;
_fillStateWithArgs = wigStartInfo._fillStateWithArgs;
}
/// <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
/// <summary>
/// Get/Set if to use the caller's security context
/// </summary>
public virtual bool UseCallerCallContext
{
get { return _useCallerCallContext; }
set { _useCallerCallContext = value; }
}
public bool UseCallerHttpContext
/// <summary>
/// Get/Set if to use the caller's HTTP context
/// </summary>
public virtual bool UseCallerHttpContext
{
get { return _useCallerHttpContext; }
set { _useCallerHttpContext = value; }
}
public bool DisposeOfStateObjects
/// <summary>
/// Get/Set if to dispose of the state object of a work item
/// </summary>
public virtual bool DisposeOfStateObjects
{
get { return _disposeOfStateObjects; }
set { _disposeOfStateObjects = value; }
}
public CallToPostExecute CallToPostExecute
/// <summary>
/// Get/Set the run the post execute options
/// </summary>
public virtual CallToPostExecute CallToPostExecute
{
get { return _callToPostExecute; }
set { _callToPostExecute = value; }
}
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
/// <summary>
/// Get/Set the default post execute callback
/// </summary>
public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback
{
get { return _postExecuteWorkItemCallback; }
set { _postExecuteWorkItemCallback = value; }
}
public bool StartSuspended
/// <summary>
/// Get/Set if the work items execution should be suspended until the Start()
/// method is called.
/// </summary>
public virtual bool StartSuspended
{
get { return _startSuspended; }
set { _startSuspended = value; }
}
}
/// <summary>
/// Get/Set the default priority that a work item gets when it is enqueued
/// </summary>
public virtual WorkItemPriority WorkItemPriority
{
get { return _workItemPriority; }
set { _workItemPriority = value; }
}
/// <summary>
/// Get/Set the if QueueWorkItem of Action<...>/Func<...> fill the
/// arguments as an object array into the state of the work item.
/// The arguments can be access later by IWorkItemResult.State.
/// </summary>
public virtual bool FillStateWithArgs
{
get { return _fillStateWithArgs; }
set { _fillStateWithArgs = value; }
}
/// <summary>
/// Get a readonly version of this WIGStartInfo
/// </summary>
/// <returns>Returns a readonly reference to this WIGStartInfoRO</returns>
public WIGStartInfo AsReadOnly()
{
return new WIGStartInfoRO(this);
}
#region WIGStartInfoRO class
/// <summary>
/// A readonly version of WIGStartInfo
/// </summary>
private class WIGStartInfoRO : WIGStartInfo
{
private readonly WIGStartInfo _wigStartInfoRO;
public WIGStartInfoRO(WIGStartInfo wigStartInfoRO)
{
_wigStartInfoRO = wigStartInfoRO;
}
/// <summary>
/// Get if to use the caller's security context
/// </summary>
public override bool UseCallerCallContext
{
get { return _wigStartInfoRO.UseCallerCallContext; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get if to use the caller's HTTP context
/// </summary>
public override bool UseCallerHttpContext
{
get { return _wigStartInfoRO.UseCallerHttpContext; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get if to dispose of the state object of a work item
/// </summary>
public override bool DisposeOfStateObjects
{
get { return _wigStartInfoRO.DisposeOfStateObjects; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get the run the post execute options
/// </summary>
public override CallToPostExecute CallToPostExecute
{
get { return _wigStartInfoRO.CallToPostExecute; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get the default post execute callback
/// </summary>
public override PostExecuteWorkItemCallback PostExecuteWorkItemCallback
{
get { return _wigStartInfoRO.PostExecuteWorkItemCallback; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get if the work items execution should be suspended until the Start()
/// method is called.
/// </summary>
public override bool StartSuspended
{
get { return _wigStartInfoRO.StartSuspended; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Get the default priority that a work item gets when it is enqueued
/// </summary>
public override WorkItemPriority WorkItemPriority
{
get { return _wigStartInfoRO.WorkItemPriority; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
/// <summary>
/// Indicate if QueueWorkItem of Action<...>/Func<...> fill the
/// arguments as an object array into the state of the work item.
/// The arguments can be access later by IWorkItemResult.State.
/// </summary>
public override bool FillStateWithArgs
{
get { return _wigStartInfoRO.FillStateWithArgs; }
set { throw new NotSupportedException("This is a readonly instance and set is not supported"); }
}
}
#endregion
}
}
+279 -107
View File
@@ -1,6 +1,3 @@
// Ami Bar
// amibar@gmail.com
using System;
using System.Threading;
using System.Diagnostics;
@@ -16,9 +13,9 @@ namespace Amib.Threading.Internal
#endregion
#region IInternalWorkItemResult interface
#region CanceledWorkItemsGroup class
public class CanceledWorkItemsGroup
public class CanceledWorkItemsGroup
{
public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup();
@@ -28,9 +25,13 @@ namespace Amib.Threading.Internal
get { return _isCanceled; }
set { _isCanceled = value; }
}
}
}
internal interface IInternalWorkItemResult
#endregion
#region IInternalWorkItemResult interface
internal interface IInternalWorkItemResult
{
event WorkItemStateCallback OnWorkItemStarted;
event WorkItemStateCallback OnWorkItemCompleted;
@@ -38,43 +39,80 @@ namespace Amib.Threading.Internal
#endregion
#region IWorkItem interface
#region IInternalWaitableResult interface
public interface IWorkItem
{
internal interface IInternalWaitableResult
{
/// <summary>
/// This method is intent for internal use.
/// </summary>
IWorkItemResult GetWorkItemResult();
}
}
#endregion
#endregion
#region IHasWorkItemPriority interface
#region WorkItem class
public interface IHasWorkItemPriority
{
WorkItemPriority WorkItemPriority { get; }
}
/// <summary>
#endregion
#region WorkItem class
/// <summary>
/// Holds a callback delegate and the state for that delegate.
/// </summary>
public class WorkItem : IHasWorkItemPriority, IWorkItem
public class WorkItem : IHasWorkItemPriority
{
#region WorkItemState enum
/// <summary>
/// Indicates the state of the work item in the thread pool
/// </summary>
private enum WorkItemState
private enum WorkItemState
{
InQueue,
InProgress,
Completed,
Canceled,
InQueue = 0, // Nexts: InProgress, Canceled
InProgress = 1, // Nexts: Completed, Canceled
Completed = 2, // Stays Completed
Canceled = 3, // Stays Canceled
}
private static bool IsValidStatesTransition(WorkItemState currentState, WorkItemState nextState)
{
bool valid = false;
switch (currentState)
{
case WorkItemState.InQueue:
valid = (WorkItemState.InProgress == nextState) || (WorkItemState.Canceled == nextState);
break;
case WorkItemState.InProgress:
valid = (WorkItemState.Completed == nextState) || (WorkItemState.Canceled == nextState);
break;
case WorkItemState.Completed:
case WorkItemState.Canceled:
// Cannot be changed
break;
default:
// Unknown state
Debug.Assert(false);
break;
}
return valid;
}
#endregion
#region Member Variables
#region Fields
/// <summary>
/// Callback delegate for the callback.
/// </summary>
private WorkItemCallback _callback;
private readonly WorkItemCallback _callback;
/// <summary>
/// State with which to call the callback delegate.
@@ -84,8 +122,9 @@ namespace Amib.Threading.Internal
/// <summary>
/// Stores the caller's context
/// </summary>
private CallerThreadContext _callerContext;
#if !(WindowsCE)
private readonly CallerThreadContext _callerContext;
#endif
/// <summary>
/// Holds the result of the mehtod
/// </summary>
@@ -104,7 +143,7 @@ namespace Amib.Threading.Internal
/// <summary>
/// A ManualResetEvent to indicate that the result is ready
/// </summary>
private ManualResetEvent _workItemCompleted;
private ManualResetEvent _workItemCompleted;
/// <summary>
/// A reference count to the _workItemCompleted.
@@ -115,12 +154,12 @@ namespace Amib.Threading.Internal
/// <summary>
/// Represents the result state of the work item
/// </summary>
private WorkItemResult _workItemResult;
private readonly WorkItemResult _workItemResult;
/// <summary>
/// Work item info
/// </summary>
private WorkItemInfo _workItemInfo;
private readonly WorkItemInfo _workItemInfo;
/// <summary>
/// Called when the WorkItem starts
@@ -138,11 +177,22 @@ namespace Amib.Threading.Internal
/// </summary>
private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
/// <summary>
/// A reference to an object that indicates whatever the
/// SmartThreadPool has been canceled
/// </summary>
private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
/// <summary>
/// The work item group this work item belong to.
///
/// </summary>
private IWorkItemsGroup _workItemsGroup;
private readonly IWorkItemsGroup _workItemsGroup;
/// <summary>
/// The thread that executes this workitem.
/// This field is available for the period when the work item is executed, before and after it is null.
/// </summary>
private Thread _executingThread;
#region Performance Counter fields
@@ -193,6 +243,8 @@ namespace Amib.Threading.Internal
/// <summary>
/// Initialize the callback holding object.
/// </summary>
/// <param name="workItemsGroup">The workItemGroup of the workitem</param>
/// <param name="workItemInfo">The WorkItemInfo of te workitem</param>
/// <param name="callback">Callback delegate for the callback.</param>
/// <param name="state">State with which to call the callback delegate.</param>
///
@@ -207,10 +259,12 @@ namespace Amib.Threading.Internal
_workItemsGroup = workItemsGroup;
_workItemInfo = workItemInfo;
#if !(WindowsCE)
if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext)
{
_callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext);
}
#endif
_callback = callback;
_state = state;
@@ -220,8 +274,11 @@ namespace Amib.Threading.Internal
internal void Initialize()
{
_workItemState = WorkItemState.InQueue;
_workItemCompleted = null;
// The _workItemState is changed directly instead of using the SetWorkItemState
// method since we don't want to go throught IsValidStateTransition.
_workItemState = WorkItemState.InQueue;
_workItemCompleted = null;
_workItemCompletedRefCount = 0;
}
@@ -237,17 +294,16 @@ namespace Amib.Threading.Internal
public CanceledWorkItemsGroup CanceledWorkItemsGroup
{
get
{
return _canceledWorkItemsGroup;
}
set
{
_canceledWorkItemsGroup = value;
}
get { return _canceledWorkItemsGroup; }
set { _canceledWorkItemsGroup = value; }
}
public CanceledWorkItemsGroup CanceledSmartThreadPool
{
get { return _canceledSmartThreadPool; }
set { _canceledSmartThreadPool = value; }
}
/// <summary>
/// Change the state of the work item to in progress if it wasn't canceled.
/// </summary>
@@ -275,6 +331,9 @@ namespace Amib.Threading.Internal
Debug.Assert(WorkItemState.InQueue == GetWorkItemState());
// No need for a lock yet, only after the state has changed to InProgress
_executingThread = Thread.CurrentThread;
SetWorkItemState(WorkItemState.InProgress);
}
@@ -321,41 +380,89 @@ namespace Amib.Threading.Internal
_workItemCompletedEvent(this);
}
}
catch // Ignore exceptions
catch // Suppress exceptions
{}
}
internal void FireWorkItemStarted()
{
try
{
if (null != _workItemStartedEvent)
{
_workItemStartedEvent(this);
}
}
catch // Suppress exceptions
{ }
}
/// <summary>
/// Execute the work item
/// </summary>
private void ExecuteWorkItem()
{
#if !(WindowsCE)
CallerThreadContext ctc = null;
if (null != _callerContext)
{
ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext);
CallerThreadContext.Apply(_callerContext);
}
#endif
Exception exception = null;
object result = null;
try
{
result = _callback(_state);
try
{
result = _callback(_state);
}
catch (Exception e)
{
// Save the exception so we can rethrow it later
exception = e;
}
// Remove the value of the execution thread, so it will not be possible to cancel the work item
// since it is already completed.
// Cancelling a work item that already completed may cause the abortion of the next work item!!!
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
if (null == executionThread)
{
// Oops! we are going to be aborted..., Wait here so we can catch the ThreadAbortException
Thread.Sleep(60*1000);
// If after 1 minute this thread was not aborted then let it continue working.
}
}
catch (Exception e)
// We must treat the ThreadAbortException or else it will be stored in the exception variable
catch (ThreadAbortException tae)
{
// Save the exception so we can rethrow it later
exception = e;
// Check if the work item was cancelled
if ((string)tae.ExceptionState == "Cancel")
{
#if !(WindowsCE)
Thread.ResetAbort();
#endif
}
}
#if !(WindowsCE)
if (null != _callerContext)
{
CallerThreadContext.Apply(ctc);
}
#endif
SetResult(result, exception);
if (!SmartThreadPool.IsWorkItemCanceled)
{
SetResult(result, exception);
}
}
/// <summary>
@@ -367,7 +474,7 @@ namespace Amib.Threading.Internal
{
try
{
_workItemInfo.PostExecuteWorkItemCallback(this._workItemResult);
_workItemInfo.PostExecuteWorkItemCallback(_workItemResult);
}
catch (Exception e)
{
@@ -380,6 +487,8 @@ namespace Amib.Threading.Internal
/// Set the result of the work item to return
/// </summary>
/// <param name="result">The result of the work item</param>
/// <param name="exception">The exception that was throw while the workitem executed, null
/// if there was no exception.</param>
internal void SetResult(object result, Exception exception)
{
_result = result;
@@ -399,33 +508,33 @@ namespace Amib.Threading.Internal
/// <summary>
/// Wait for all work items to complete
/// </summary>
/// <param name="workItemResults">Array of work item result objects</param>
/// <param name="waitableResults">Array of work item result objects</param>
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</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 wait if needed</param>
/// <returns>
/// true when every work item in workItemResults has completed; otherwise false.
/// true when every work item in waitableResults has completed; otherwise false.
/// </returns>
internal static bool WaitAll(
IWorkItemResult [] workItemResults,
IWaitableResult[] waitableResults,
int millisecondsTimeout,
bool exitContext,
WaitHandle cancelWaitHandle)
{
if (0 == workItemResults.Length)
if (0 == waitableResults.Length)
{
return true;
}
bool success;
WaitHandle [] waitHandles = new WaitHandle[workItemResults.Length];;
GetWaitHandles(workItemResults, waitHandles);
WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length];
GetWaitHandles(waitableResults, waitHandles);
if ((null == cancelWaitHandle) && (waitHandles.Length <= 64))
{
success = WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
success = EventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
}
else
{
@@ -448,7 +557,7 @@ namespace Amib.Threading.Internal
// We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle
// won't affect it.
// Each iteration we update the time left for the timeout.
for(int i = 0; i < workItemResults.Length; ++i)
for (int i = 0; i < waitableResults.Length; ++i)
{
// WaitAny don't work with negative numbers
if (!waitInfinitely && (millisecondsLeft < 0))
@@ -458,8 +567,8 @@ namespace Amib.Threading.Internal
}
whs[0] = waitHandles[i];
int result = WaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
if((result > 0) || (WaitHandle.WaitTimeout == result))
int result = EventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
if ((result > 0) || (EventWaitHandle.WaitTimeout == result))
{
success = false;
break;
@@ -474,7 +583,7 @@ namespace Amib.Threading.Internal
}
}
// Release the wait handles
ReleaseWaitHandles(workItemResults);
ReleaseWaitHandles(waitableResults);
return success;
}
@@ -482,7 +591,7 @@ namespace Amib.Threading.Internal
/// <summary>
/// Waits for any of the work items in the specified array to complete, cancel, or timeout
/// </summary>
/// <param name="workItemResults">Array of work item result objects</param>
/// <param name="waitableResults">Array of work item result objects</param>
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</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.
@@ -491,38 +600,38 @@ namespace Amib.Threading.Internal
/// <returns>
/// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
/// </returns>
internal static int WaitAny(
IWorkItemResult [] workItemResults,
internal static int WaitAny(
IWaitableResult[] waitableResults,
int millisecondsTimeout,
bool exitContext,
WaitHandle cancelWaitHandle)
{
WaitHandle [] waitHandles = null;
WaitHandle [] waitHandles;
if (null != cancelWaitHandle)
{
waitHandles = new WaitHandle[workItemResults.Length+1];
GetWaitHandles(workItemResults, waitHandles);
waitHandles[workItemResults.Length] = cancelWaitHandle;
waitHandles = new WaitHandle[waitableResults.Length + 1];
GetWaitHandles(waitableResults, waitHandles);
waitHandles[waitableResults.Length] = cancelWaitHandle;
}
else
{
waitHandles = new WaitHandle[workItemResults.Length];
GetWaitHandles(workItemResults, waitHandles);
waitHandles = new WaitHandle[waitableResults.Length];
GetWaitHandles(waitableResults, waitHandles);
}
int result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
int result = EventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
// Treat cancel as timeout
if (null != cancelWaitHandle)
{
if (result == workItemResults.Length)
if (result == waitableResults.Length)
{
result = WaitHandle.WaitTimeout;
result = EventWaitHandle.WaitTimeout;
}
}
ReleaseWaitHandles(workItemResults);
ReleaseWaitHandles(waitableResults);
return result;
}
@@ -530,16 +639,16 @@ namespace Amib.Threading.Internal
/// <summary>
/// Fill an array of wait handles with the work items wait handles.
/// </summary>
/// <param name="workItemResults">An array of work item results</param>
/// <param name="waitableResults">An array of work item results</param>
/// <param name="waitHandles">An array of wait handles to fill</param>
private static void GetWaitHandles(
IWorkItemResult [] workItemResults,
IWaitableResult[] waitableResults,
WaitHandle [] waitHandles)
{
for(int i = 0; i < workItemResults.Length; ++i)
for (int i = 0; i < waitableResults.Length; ++i)
{
WorkItemResult wir = workItemResults[i] as WorkItemResult;
Debug.Assert(null != wir, "All workItemResults must be WorkItemResult objects");
WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult;
Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects");
waitHandles[i] = wir.GetWorkItem().GetWaitHandle();
}
@@ -548,31 +657,40 @@ namespace Amib.Threading.Internal
/// <summary>
/// Release the work items' wait handles
/// </summary>
/// <param name="workItemResults">An array of work item results</param>
private static void ReleaseWaitHandles(IWorkItemResult [] workItemResults)
/// <param name="waitableResults">An array of work item results</param>
private static void ReleaseWaitHandles(IWaitableResult[] waitableResults)
{
for(int i = 0; i < workItemResults.Length; ++i)
for (int i = 0; i < waitableResults.Length; ++i)
{
WorkItemResult wir = workItemResults[i] as WorkItemResult;
WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult();
wir.GetWorkItem().ReleaseWaitHandle();
}
}
#endregion
#region Private Members
private WorkItemState GetWorkItemState()
private WorkItemState GetWorkItemState()
{
if (_canceledWorkItemsGroup.IsCanceled)
{
return WorkItemState.Canceled;
}
return _workItemState;
lock (this)
{
if (WorkItemState.Completed == _workItemState || WorkItemState.InProgress == _workItemState)
{
return _workItemState;
}
if (CanceledSmartThreadPool.IsCanceled || CanceledWorkItemsGroup.IsCanceled)
{
return WorkItemState.Canceled;
}
return _workItemState;
}
}
/// <summary>
/// Sets the work item's state
/// </summary>
@@ -581,7 +699,10 @@ namespace Amib.Threading.Internal
{
lock(this)
{
_workItemState = workItemState;
if (IsValidStatesTransition(_workItemState, workItemState))
{
_workItemState = workItemState;
}
}
}
@@ -615,29 +736,61 @@ namespace Amib.Threading.Internal
/// 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>
private bool Cancel()
private bool Cancel(bool abortExecution)
{
lock(this)
#if (WindowsCE)
if(abortExecution)
{
throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature");
}
#endif
bool success = false;
bool signalComplete = false;
lock (this)
{
switch(GetWorkItemState())
{
case WorkItemState.Canceled:
//Debug.WriteLine("Work item already canceled");
return true;
success = true;
break;
case WorkItemState.Completed:
case WorkItemState.InProgress:
//Debug.WriteLine("Work item cannot be canceled");
return false;
//Debug.WriteLine("Work item cannot be canceled");
break;
case WorkItemState.InProgress:
if (abortExecution)
{
Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread);
if (null != executionThread)
{
executionThread.Abort("Cancel");
success = true;
signalComplete = true;
}
}
else
{
success = true;
signalComplete = true;
}
break;
case WorkItemState.InQueue:
// Signal to the wait for completion that the work
// item has been completed (canceled). There is no
// reason to wait for it to get out of the queue
SignalComplete(true);
signalComplete = true;
//Debug.WriteLine("Work item canceled");
return true;
success = true;
break;
}
if (signalComplete)
{
SignalComplete(true);
}
}
return false;
return success;
}
/// <summary>
@@ -651,7 +804,7 @@ namespace Amib.Threading.Internal
bool exitContext,
WaitHandle cancelWaitHandle)
{
Exception e = null;
Exception e;
object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
if (null != e)
{
@@ -704,7 +857,7 @@ namespace Amib.Threading.Internal
else
{
WaitHandle wh = GetWaitHandle();
int result = WaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
int result = EventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
ReleaseWaitHandle();
switch(result)
@@ -715,7 +868,7 @@ namespace Amib.Threading.Internal
// work item (not the get result)
break;
case 1:
case WaitHandle.WaitTimeout:
case EventWaitHandle.WaitTimeout:
throw new WorkItemTimeoutException("Work item timeout");
default:
Debug.Assert(false);
@@ -747,7 +900,7 @@ namespace Amib.Threading.Internal
{
if (null == _workItemCompleted)
{
_workItemCompleted = new ManualResetEvent(IsCompleted);
_workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted);
}
++_workItemCompletedRefCount;
}
@@ -844,12 +997,12 @@ namespace Amib.Threading.Internal
#region WorkItemResult class
private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult
private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult
{
/// <summary>
/// A back reference to the work item
/// </summary>
private WorkItem _workItem;
private readonly WorkItem _workItem;
public WorkItemResult(WorkItem workItem)
{
@@ -929,11 +1082,16 @@ namespace Amib.Threading.Internal
return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e);
}
public bool Cancel()
public bool Cancel()
{
return _workItem.Cancel();
return Cancel(false);
}
public bool Cancel(bool abortExecution)
{
return _workItem.Cancel(abortExecution);
}
public object State
{
get
@@ -998,7 +1156,21 @@ namespace Amib.Threading.Internal
}
#endregion
}
#region IInternalWorkItemResult Members
public IWorkItemResult GetWorkItemResult()
{
return this;
}
public IWorkItemResult<TResult> GetWorkItemResultT<TResult>()
{
return new WorkItemResultTWrapper<TResult>(this);
}
#endregion
}
#endregion
+33 -23
View File
@@ -1,6 +1,3 @@
// Ami Bar
// amibar@gmail.com
using System;
namespace Amib.Threading.Internal
@@ -12,6 +9,7 @@ namespace Amib.Threading.Internal
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="callback">A callback to execute</param>
/// <returns>Returns a work item</returns>
@@ -26,7 +24,8 @@ namespace Amib.Threading.Internal
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
/// <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>
@@ -42,7 +41,8 @@ namespace Amib.Threading.Internal
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
/// <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>
@@ -63,7 +63,8 @@ namespace Amib.Threading.Internal
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="workItemsGroup">The WorkItemsGroup of this workitem</param>
/// <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.
@@ -76,13 +77,14 @@ namespace Amib.Threading.Internal
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;
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
WorkItem workItem = new WorkItem(
workItemsGroup,
@@ -95,6 +97,7 @@ namespace Amib.Threading.Internal
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="workItemsGroup">The work items group</param>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
@@ -131,6 +134,7 @@ namespace Amib.Threading.Internal
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="workItemsGroup">The work items group</param>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="workItemInfo">Work item information</param>
/// <param name="callback">A callback to execute</param>
@@ -138,28 +142,29 @@ namespace Amib.Threading.Internal
/// 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);
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);
WorkItem workItem = new WorkItem(
workItemsGroup,
new WorkItemInfo(workItemInfo),
callback,
state);
return workItem;
}
return workItem;
}
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="workItemsGroup">The work items group</param>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
@@ -185,6 +190,7 @@ namespace Amib.Threading.Internal
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
WorkItem workItem = new WorkItem(
workItemsGroup,
@@ -198,6 +204,7 @@ namespace Amib.Threading.Internal
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="workItemsGroup">The work items group</param>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
@@ -239,6 +246,7 @@ namespace Amib.Threading.Internal
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="workItemsGroup">The work items group</param>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
@@ -266,6 +274,7 @@ namespace Amib.Threading.Internal
workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
workItemInfo.CallToPostExecute = callToPostExecute;
workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority;
WorkItem workItem = new WorkItem(
workItemsGroup,
@@ -279,6 +288,7 @@ namespace Amib.Threading.Internal
/// <summary>
/// Create a new work item
/// </summary>
/// <param name="workItemsGroup">The work items group</param>
/// <param name="wigStartInfo">Work item group start information</param>
/// <param name="callback">A callback to execute</param>
/// <param name="state">
+24 -9
View File
@@ -1,6 +1,3 @@
// Ami Bar
// amibar@gmail.com
namespace Amib.Threading
{
#region WorkItemInfo class
@@ -61,37 +58,55 @@ namespace Amib.Threading
_workItemPriority = workItemInfo._workItemPriority;
}
public bool UseCallerCallContext
/// <summary>
/// Get/Set if to use the caller's security context
/// </summary>
public bool UseCallerCallContext
{
get { return _useCallerCallContext; }
set { _useCallerCallContext = value; }
}
public bool UseCallerHttpContext
/// <summary>
/// Get/Set if to use the caller's HTTP context
/// </summary>
public bool UseCallerHttpContext
{
get { return _useCallerHttpContext; }
set { _useCallerHttpContext = value; }
}
public bool DisposeOfStateObjects
/// <summary>
/// Get/Set if to dispose of the state object of a work item
/// </summary>
public bool DisposeOfStateObjects
{
get { return _disposeOfStateObjects; }
set { _disposeOfStateObjects = value; }
}
public CallToPostExecute CallToPostExecute
/// <summary>
/// Get/Set the run the post execute options
/// </summary>
public CallToPostExecute CallToPostExecute
{
get { return _callToPostExecute; }
set { _callToPostExecute = value; }
}
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
/// <summary>
/// Get/Set the post execute callback
/// </summary>
public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
{
get { return _postExecuteWorkItemCallback; }
set { _postExecuteWorkItemCallback = value; }
}
public WorkItemPriority WorkItemPriority
/// <summary>
/// Get/Set the work items priority
/// </summary>
public WorkItemPriority WorkItemPriority
{
get { return _workItemPriority; }
set { _workItemPriority = value; }
+128
View File
@@ -0,0 +1,128 @@
using System;
using System.Threading;
namespace Amib.Threading.Internal
{
#region WorkItemResultTWrapper class
internal class WorkItemResultTWrapper<TResult> : IWorkItemResult<TResult>, IInternalWaitableResult
{
private readonly IWorkItemResult _workItemResult;
public WorkItemResultTWrapper(IWorkItemResult workItemResult)
{
_workItemResult = workItemResult;
}
#region IWorkItemResult<TResult> Members
public TResult GetResult()
{
return (TResult)_workItemResult.GetResult();
}
public TResult GetResult(int millisecondsTimeout, bool exitContext)
{
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext);
}
public TResult GetResult(TimeSpan timeout, bool exitContext)
{
return (TResult)_workItemResult.GetResult(timeout, exitContext);
}
public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
{
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
}
public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
{
return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle);
}
public TResult GetResult(out Exception e)
{
return (TResult)_workItemResult.GetResult(out e);
}
public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
{
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e);
}
public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e)
{
return (TResult)_workItemResult.GetResult(timeout, exitContext, out e);
}
public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
{
return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
}
public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
{
return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e);
}
public bool IsCompleted
{
get { return _workItemResult.IsCompleted; }
}
public bool IsCanceled
{
get { return _workItemResult.IsCanceled; }
}
public object State
{
get { return _workItemResult.State; }
}
public bool Cancel()
{
return _workItemResult.Cancel();
}
public bool Cancel(bool abortExecution)
{
return _workItemResult.Cancel(abortExecution);
}
public WorkItemPriority WorkItemPriority
{
get { return _workItemResult.WorkItemPriority; }
}
public TResult Result
{
get { return (TResult)_workItemResult.Result; }
}
public object Exception
{
get { return (TResult)_workItemResult.Exception; }
}
#region IInternalWorkItemResult Members
public IWorkItemResult GetWorkItemResult()
{
return _workItemResult.GetWorkItemResult();
}
public IWorkItemResult<TRes> GetWorkItemResultT<TRes>()
{
return (IWorkItemResult<TRes>)this;
}
#endregion
#endregion
}
#endregion
}
+153 -304
View File
@@ -1,6 +1,3 @@
// Ami Bar
// amibar@gmail.com
using System;
using System.Threading;
using System.Runtime.CompilerServices;
@@ -8,33 +5,34 @@ using System.Diagnostics;
namespace Amib.Threading.Internal
{
#region WorkItemsGroup class
/// <summary>
/// Summary description for WorkItemsGroup.
/// </summary>
public class WorkItemsGroup : IWorkItemsGroup
public class WorkItemsGroup : WorkItemsGroupBase
{
#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";
private readonly object _lock = new object();
/// <summary>
/// A reference to the SmartThreadPool instance that created this
/// WorkItemsGroup.
/// </summary>
private SmartThreadPool _stp;
private readonly SmartThreadPool _stp;
/// <summary>
/// The OnIdle event
/// </summary>
private event WorkItemsGroupIdleHandler _onIdle;
/// <summary>
/// A flag to indicate if the Work Items Group is now suspended.
/// </summary>
private bool _isSuspended;
/// <summary>
/// Defines how many work items of this WorkItemsGroup can run at once.
/// </summary>
@@ -44,7 +42,7 @@ namespace Amib.Threading.Internal
/// Priority queue to hold work items before they are passed
/// to the SmartThreadPool.
/// </summary>
private PriorityQueue _workItemsQueue;
private readonly PriorityQueue _workItemsQueue;
/// <summary>
/// Indicate how many work items are waiting in the SmartThreadPool
@@ -63,12 +61,13 @@ namespace Amib.Threading.Internal
/// <summary>
/// WorkItemsGroup start information
/// </summary>
private WIGStartInfo _workItemsGroupStartInfo;
private readonly WIGStartInfo _workItemsGroupStartInfo;
/// <summary>
/// Signaled when all of the WorkItemsGroup's work item completed.
/// </summary>
private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
//private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true);
/// <summary>
/// A common object for all the work items that this work items group
@@ -80,322 +79,156 @@ namespace Amib.Threading.Internal
#region Construction
public WorkItemsGroup(
public WorkItemsGroup(
SmartThreadPool stp,
int concurrency,
WIGStartInfo wigStartInfo)
{
if (concurrency <= 0)
{
throw new ArgumentOutOfRangeException("concurrency", concurrency, "concurrency must be greater than zero");
throw new ArgumentOutOfRangeException(
"concurrency",
#if !(WindowsCE)
concurrency,
#endif
"concurrency must be greater than zero");
}
_stp = stp;
_concurrency = concurrency;
_workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo);
_workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly();
_workItemsQueue = new PriorityQueue();
Name = "WorkItemsGroup";
// The _workItemsInStpQueue gets the number of currently executing work items,
// because once a work item is executing, it cannot be cancelled.
_workItemsInStpQueue = _workItemsExecutingInStp;
_isSuspended = _workItemsGroupStartInfo.StartSuspended;
}
#endregion
#region IWorkItemsGroup implementation
#region WorkItemsGroupBase Overrides
/// <summary>
/// Get/Set the name of the SmartThreadPool instance
/// </summary>
public string Name
{
get
{
return _name;
}
public override int Concurrency
{
get { return _concurrency; }
set
{
Debug.Assert(value > 0);
set
{
_name = value;
}
}
int diff = value - _concurrency;
_concurrency = value;
if (diff > 0)
{
EnqueueToSTPNextNWorkItem(diff);
}
}
}
/// <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();
}
public override int WaitingCallbacks
{
get { return _workItemsQueue.Count; }
}
/// <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();
}
public override object[] GetStates()
{
lock (_lock)
{
object[] states = new object[_workItemsQueue.Count];
int i = 0;
foreach (WorkItem workItem in _workItemsQueue)
{
states[i] = workItem.GetWorkItemResult().State;
++i;
}
return states;
}
}
/// <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>
/// WorkItemsGroup start information
/// </summary>
public override WIGStartInfo WIGStartInfo
{
get { return _workItemsGroupStartInfo; }
}
/// <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;
}
/// <summary>
/// Start the Work Items Group if it was started suspended
/// </summary>
public override void Start()
{
// If the Work Items Group already started then quit
if (!_isSuspended)
{
return;
}
_isSuspended = false;
for(int i = 0; i < _concurrency; ++i)
{
EnqueueToSTPNextWorkItem(null, false);
}
EnqueueToSTPNextNWorkItem(_concurrency);
}
public override void Cancel(bool abortExecution)
{
lock (_lock)
{
_canceledWorkItemsGroup.IsCanceled = true;
_workItemsQueue.Clear();
_workItemsInStpQueue = 0;
_canceledWorkItemsGroup = new CanceledWorkItemsGroup();
}
if (abortExecution)
{
_stp.CancelAbortWorkItemsGroup(this);
}
}
/// <summary>
/// Wait for the thread pool to be idle
/// </summary>
public override bool WaitForIdle(int millisecondsTimeout)
{
SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this);
return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false);
}
public override event WorkItemsGroupIdleHandler OnIdle
{
add { _onIdle += value; }
remove { _onIdle -= value; }
}
#endregion
#endregion
#region Private methods
private void RegisterToWorkItemCompletion(IWorkItemResult wir)
private void RegisterToWorkItemCompletion(IWorkItemResult wir)
{
IInternalWorkItemResult iwir = wir as IInternalWorkItemResult;
iwir.OnWorkItemStarted += new WorkItemStateCallback(OnWorkItemStartedCallback);
iwir.OnWorkItemCompleted += new WorkItemStateCallback(OnWorkItemCompletedCallback);
IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir;
iwir.OnWorkItemStarted += OnWorkItemStartedCallback;
iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback;
}
public void OnSTPIsStarting()
public void OnSTPIsStarting()
{
lock (this)
{
if (_workItemsGroupStartInfo.StartSuspended)
{
return;
}
}
if (_isSuspended)
{
return;
}
for(int i = 0; i < _concurrency; ++i)
{
EnqueueToSTPNextWorkItem(null, false);
}
EnqueueToSTPNextNWorkItem(_concurrency);
}
public void EnqueueToSTPNextNWorkItem(int count)
{
for (int i = 0; i < count; ++i)
{
EnqueueToSTPNextWorkItem(null, false);
}
}
private object FireOnIdle(object state)
{
FireOnIdleImpl(_onIdle);
@@ -417,8 +250,7 @@ namespace Amib.Threading.Internal
{
eh(this);
}
// Ignore exceptions
catch{}
catch { } // Suppress exceptions
}
}
@@ -435,7 +267,12 @@ namespace Amib.Threading.Internal
EnqueueToSTPNextWorkItem(null, true);
}
private void EnqueueToSTPNextWorkItem(WorkItem workItem)
internal override void Enqueue(WorkItem workItem)
{
EnqueueToSTPNextWorkItem(workItem);
}
private void EnqueueToSTPNextWorkItem(WorkItem workItem)
{
EnqueueToSTPNextWorkItem(workItem, false);
}
@@ -475,8 +312,8 @@ namespace Amib.Threading.Internal
(0 == _workItemsInStpQueue))
{
_stp.RegisterWorkItemsGroup(this);
Trace.WriteLine("WorkItemsGroup " + Name + " is NOT idle");
_isIdleWaitHandle.Reset();
IsIdle = false;
_isIdleWaitHandle.Reset();
}
}
@@ -486,19 +323,31 @@ namespace Amib.Threading.Internal
if (0 == _workItemsInStpQueue)
{
_stp.UnregisterWorkItemsGroup(this);
Trace.WriteLine("WorkItemsGroup " + Name + " is idle");
_isIdleWaitHandle.Set();
_stp.QueueWorkItem(new WorkItemCallback(this.FireOnIdle));
IsIdle = true;
_isIdleWaitHandle.Set();
if (decrementWorkItemsInStpQueue)
{
_stp.QueueWorkItem(new WorkItemCallback(FireOnIdle));
}
}
return;
}
if (!_workItemsGroupStartInfo.StartSuspended)
if (!_isSuspended)
{
if (_workItemsInStpQueue < _concurrency)
{
WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
_stp.Enqueue(nextWorkItem, true);
try
{
_stp.Enqueue(nextWorkItem);
}
catch (ObjectDisposedException e)
{
e.GetHashCode();
// The STP has been shutdown
}
++_workItemsInStpQueue;
}
}
@@ -506,7 +355,7 @@ namespace Amib.Threading.Internal
}
#endregion
}
}
#endregion
}
+448
View File
@@ -0,0 +1,448 @@
using System;
using System.Threading;
namespace Amib.Threading.Internal
{
public abstract class WorkItemsGroupBase : IWorkItemsGroup
{
#region Private Fields
/// <summary>
/// Contains the name of this instance of SmartThreadPool.
/// Can be changed by the user.
/// </summary>
private string _name = "WorkItemsGroupBase";
/// <summary>
/// Inidcates if the SmartThreadPool/WorkItemsGroup is idle.
/// Its value is true if the _isIdleWaitHandle is set.
/// </summary>
private bool _isIdle = true;
#endregion
#region IWorkItemsGroup Members
#region Public Methods
/// <summary>
/// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
}
#endregion
#region Abstract Methods
public abstract int Concurrency { get; set; }
public abstract int WaitingCallbacks { get; }
public abstract object[] GetStates();
public abstract WIGStartInfo WIGStartInfo { get; }
public abstract void Start();
public abstract void Cancel(bool abortExecution);
public abstract bool WaitForIdle(int millisecondsTimeout);
public abstract event WorkItemsGroupIdleHandler OnIdle;
internal abstract void Enqueue(WorkItem workItem);
internal virtual void PreQueueWorkItem() { }
#endregion
#region Common Base Methods
/// <summary>
/// Cancel all the work items.
/// Same as Cancel(false)
/// </summary>
public virtual void Cancel()
{
Cancel(false);
}
/// <summary>
/// Wait for the SmartThreadPool/WorkItemsGroup to be idle
/// </summary>
public void WaitForIdle()
{
WaitForIdle(Timeout.Infinite);
}
/// <summary>
/// Wait for the SmartThreadPool/WorkItemsGroup to be idle
/// </summary>
public bool WaitForIdle(TimeSpan timeout)
{
return WaitForIdle((int)timeout.TotalMilliseconds);
}
/// <summary>
/// IsIdle is true when there are no work items running or queued.
/// </summary>
public bool IsIdle
{
get { return _isIdle; }
protected set { _isIdle = value; }
}
#endregion
#region QueueWorkItem
/// <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, WIGStartInfo, callback);
Enqueue(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)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority);
Enqueue(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)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback);
Enqueue(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, WIGStartInfo, callback, state);
Enqueue(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)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority);
Enqueue(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)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state);
Enqueue(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)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback);
Enqueue(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)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
Enqueue(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)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
Enqueue(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)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
#endregion
#region QueueWorkItem(Action<...>)
public IWorkItemResult QueueWorkItem(Action action)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
delegate
{
action.Invoke();
return null;
});
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
public IWorkItemResult QueueWorkItem<T>(Action<T> action, T arg)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
delegate
{
action.Invoke(arg);
return null;
},
WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
public IWorkItemResult QueueWorkItem<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
delegate
{
action.Invoke(arg1, arg2);
return null;
},
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
public IWorkItemResult QueueWorkItem<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
delegate
{
action.Invoke(arg1, arg2, arg3);
return null;
},
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
public IWorkItemResult QueueWorkItem<T1, T2, T3, T4>(
Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
delegate
{
action.Invoke(arg1, arg2, arg3, arg4);
return null;
},
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null);
Enqueue(workItem);
return workItem.GetWorkItemResult();
}
#endregion
#region QueueWorkItem(Func<...>)
public IWorkItemResult<TResult> QueueWorkItem<TResult>(Func<TResult> func)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
delegate
{
return func.Invoke();
});
Enqueue(workItem);
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
}
public IWorkItemResult<TResult> QueueWorkItem<T, TResult>(Func<T, TResult> func, T arg)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
delegate
{
return func.Invoke(arg);
},
WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null);
Enqueue(workItem);
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
}
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
delegate
{
return func.Invoke(arg1, arg2);
},
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null);
Enqueue(workItem);
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
}
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, TResult>(
Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
delegate
{
return func.Invoke(arg1, arg2, arg3);
},
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null);
Enqueue(workItem);
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
}
public IWorkItemResult<TResult> QueueWorkItem<T1, T2, T3, T4, TResult>(
Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
PreQueueWorkItem();
WorkItem workItem = WorkItemFactory.CreateWorkItem(
this,
WIGStartInfo,
delegate
{
return func.Invoke(arg1, arg2, arg3, arg4);
},
WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null);
Enqueue(workItem);
return new WorkItemResultTWrapper<TResult>(workItem.GetWorkItemResult());
}
#endregion
#endregion
}
}
+92 -66
View File
@@ -1,6 +1,3 @@
// Ami Bar
// amibar@gmail.com
using System;
using System.Threading;
@@ -18,7 +15,7 @@ namespace Amib.Threading.Internal
/// <summary>
/// Waiters queue (implemented as stack).
/// </summary>
private WaiterEntry _headWaiterEntry = new WaiterEntry();
private readonly WaiterEntry _headWaiterEntry = new WaiterEntry();
/// <summary>
/// Waiters count
@@ -28,20 +25,50 @@ namespace Amib.Threading.Internal
/// <summary>
/// Work items queue
/// </summary>
private PriorityQueue _workItems = new PriorityQueue();
private readonly 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>
#if (WindowsCE)
private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot();
#else
[ThreadStatic]
private static WaiterEntry _waiterEntry;
#endif
/// <summary>
/// Each thread in the thread pool keeps its own waiter entry.
/// </summary>
private static WaiterEntry CurrentWaiterEntry
{
#if (WindowsCE)
get
{
return Thread.GetData(_waiterEntrySlot) as WaiterEntry;
}
set
{
Thread.SetData(_waiterEntrySlot, value);
}
#else
get
{
return _waiterEntry;
}
set
{
_waiterEntry = value;
}
#endif
}
/// <summary>
/// A flag that indicates if the WorkItemsQueue has been disposed.
/// </summary>
private bool _isDisposed = false;
@@ -57,11 +84,7 @@ namespace Amib.Threading.Internal
{
get
{
lock(this)
{
ValidateNotDisposed();
return _workItems.Count;
}
return _workItems.Count;
}
}
@@ -72,11 +95,7 @@ namespace Amib.Threading.Internal
{
get
{
lock(this)
{
ValidateNotDisposed();
return _waitersCount;
}
return _waitersCount;
}
}
@@ -144,19 +163,19 @@ namespace Amib.Threading.Internal
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.
// 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;
WaiterEntry waiterEntry;
WorkItem workItem = null;
lock(this)
@@ -169,19 +188,18 @@ namespace Amib.Threading.Internal
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);
}
// No waiting work items ...
// 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 [] {
WaitHandle [] waitHandles = new WaitHandle[] {
waiterEntry.WaitHandle,
cancelEvent };
@@ -189,10 +207,10 @@ namespace Amib.Threading.Internal
// 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)
// It just doesn't work, I don't know why, so I have two lock(this)
// statments insted of one.
int index = WaitHandle.WaitAny(
int index = EventWaitHandle.WaitAny(
waitHandles,
millisecondsTimeout,
true);
@@ -242,7 +260,7 @@ namespace Amib.Threading.Internal
/// Cleanup the work items queue, hence no more work
/// items are allowed to be queue
/// </summary>
protected virtual void Cleanup()
private void Cleanup()
{
lock(this)
{
@@ -279,6 +297,21 @@ namespace Amib.Threading.Internal
}
}
public object[] GetStates()
{
lock (this)
{
object[] states = new object[_workItems.Count];
int i = 0;
foreach (WorkItem workItem in _workItems)
{
states[i] = workItem.GetWorkItemResult().State;
++i;
}
return states;
}
}
#endregion
#region Private methods
@@ -289,14 +322,14 @@ namespace Amib.Threading.Internal
/// <returns></returns>
/// In order to avoid creation and destuction of WaiterEntry
/// objects each thread has its own WaiterEntry object.
private WaiterEntry GetThreadWaiterEntry()
private static WaiterEntry GetThreadWaiterEntry()
{
if (null == _waiterEntry)
if (null == CurrentWaiterEntry)
{
_waiterEntry = new WaiterEntry();
CurrentWaiterEntry = new WaiterEntry();
}
_waiterEntry.Reset();
return _waiterEntry;
CurrentWaiterEntry.Reset();
return CurrentWaiterEntry;
}
#region Waiters stack methods
@@ -418,14 +451,15 @@ namespace Amib.Threading.Internal
#region WaiterEntry class
// A waiter entry in the _waiters queue.
public class WaiterEntry : IDisposable
public sealed 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);
//private AutoResetEvent _waitHandle = new AutoResetEvent(false);
private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent();
/// <summary>
/// Flag to know if this waiter already quited from the queue
@@ -550,16 +584,14 @@ namespace Amib.Threading.Internal
public void Dispose()
{
if (!_isDisposed)
lock (this)
{
Close();
if (!_isDisposed)
{
Close();
}
_isDisposed = true;
}
}
~WaiterEntry()
{
Dispose();
}
#endregion
@@ -574,14 +606,8 @@ namespace Amib.Threading.Internal
if (!_isDisposed)
{
Cleanup();
_isDisposed = true;
GC.SuppressFinalize(this);
}
}
~WorkItemsQueue()
{
Cleanup();
_isDisposed = true;
}
private void ValidateNotDisposed()
File diff suppressed because it is too large Load Diff
+46 -370
View File
@@ -3,7 +3,7 @@
<!--
Microsoft ResX Schema
Version 1.3
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
@@ -14,16 +14,17 @@
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="version">2.0</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="Name1"><value>this is my long string</value><comment>this is a comment</comment></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]
<value>[base64 mime encoded serialized .NET Framework object]</value>
</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]
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
@@ -35,7 +36,7 @@
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used forserialized objects, and tells the
The mimetype is used for serialized 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:
@@ -45,7 +46,7 @@
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
@@ -59,18 +60,37 @@
: 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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<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="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
@@ -89,378 +109,34 @@
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.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>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.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">
<metadata name="timerPoll.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.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">
</metadata>
<metadata name="pcActiveThreads.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.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">
</metadata>
<metadata name="pcInUseThreads.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.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">
</metadata>
<metadata name="pcQueuedWorkItems.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.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">
</metadata>
<metadata name="pcCompletedWorkItems.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.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">
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>87</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAIAICAQAAAAAADoAgAAJgAAABAQEAAAAAAAKAEAAA4DAAAoAAAAIAAAAEAAAAABAAQAAAAAAAAC
AAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/
@@ -71,6 +71,16 @@
<DebugType>none</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseCE|AnyCPU' ">
<OutputPath>bin\ReleaseCE\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<BaseAddress>285212672</BaseAddress>
<Optimize>true</Optimize>
<DebugType>
</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System">
<Name>System</Name>
+63
View File
@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.42
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace UsageControl.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UsageControl.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
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">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</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 for serialized 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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<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" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</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>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+59
View File
@@ -0,0 +1,59 @@
namespace UsageControl
{
partial class QueueUsageControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (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()
{
this.components = new System.ComponentModel.Container();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 500;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// QueueUsageControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Transparent;
this.Name = "QueueUsageControl";
this.Size = new System.Drawing.Size(167, 247);
this.Resize += new System.EventHandler(this.QueueUsageControl_Resize);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Timer timer1;
}
}
+342
View File
@@ -0,0 +1,342 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using System.Reflection;
using System.Drawing.Imaging;
namespace UsageControl
{
public partial class QueueUsageControl : UserControl
{
private List<QueueUsageEntry> _queuedItems;
private int _maxItemsVisible = 0;
private int _lastVisibleItemIndex = 0;
private int _itemHeight = 0;
private Dictionary<Color, Bitmap> _imagesCache = new Dictionary<Color, Bitmap>();
private GraphicsPath _pathBorder;
private RectangleF [] _slots;
private bool _invalidate = true;
public QueueUsageControl()
{
//Debug.WriteLine("QueueUsageControl");
EnableDoubleBuffering();
Reset();
InitializeComponent();
ControlRezised();
}
public static Bitmap GenerateItemImage(string text, Color color, int width, int height, Font font)
{
//Debug.WriteLine("GenerateItemImage");
Bitmap itemImage = null;
Rectangle rc = new Rectangle(0, 0, width, height);
itemImage = new Bitmap(rc.Width, rc.Height);
/// Create button
rc.Inflate(-3, -3);
GraphicsPath path1 = GetPath(rc, 10);
rc.Inflate(0, 6);
LinearGradientBrush br1 = new LinearGradientBrush(rc, color, Color.White, LinearGradientMode.Vertical);
rc.Inflate(0, -6);
/// Create shadow
Rectangle rc2 = rc;
rc2.Offset(8, 8);
GraphicsPath path2 = GetPath(rc2, 20);
PathGradientBrush br2 = new PathGradientBrush(path2);
br2.CenterColor = ControlPaint.DarkDark(Color.Silver);
br2.SurroundColors = new Color[] { Color.White };
/// Create bubble
Rectangle rc3 = rc;
rc3.Inflate(-15, -rc.Height / 3);
rc3.Y = rc3.Y - 2;
//rc3.Height = rc3.Height;
GraphicsPath path3 = GetPath(rc3, rc3.Height);
LinearGradientBrush br3 = new LinearGradientBrush(rc3, Color.FromArgb(255, Color.White), Color.FromArgb(0, Color.White), LinearGradientMode.Vertical);
itemImage = new Bitmap(width - 2, height);
Graphics g = Graphics.FromImage(itemImage);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.FillPath(br2, path2);
g.FillPath(br1, path1);
g.FillPath(br3, path3);
//SizeF size = g.MeasureString(text, font);
//int fontHeight = (int)size.Height + 5;
//g.DrawString(
// text,
// font,
// Brushes.Black,
// new RectangleF((rc.Width - size.Width) / 2, 2, width, fontHeight));
return itemImage;
}
private Bitmap GetItemsImage(Color color)
{
//Debug.WriteLine("GetItemsImage");
Bitmap itemImage = null;
if (!_imagesCache.ContainsKey(color))
{
Rectangle rc = new Rectangle(0, 0, this.Width, _itemHeight);
itemImage = new Bitmap(rc.Width, rc.Height);
/// Create button
rc.Inflate(-3, -3);
GraphicsPath path1 = GetPath(rc, 10);
rc.Inflate(0, 6);
LinearGradientBrush br1 = new LinearGradientBrush(rc, color, Color.White, LinearGradientMode.Vertical);
rc.Inflate(0, -6);
/// Create shadow
Rectangle rc2 = rc;
rc2.Offset(8, 8);
GraphicsPath path2 = GetPath(rc2, 20);
PathGradientBrush br2 = new PathGradientBrush(path2);
br2.CenterColor = ControlPaint.DarkDark(Color.Silver);
br2.SurroundColors = new Color[] { Color.White };
/// Create bubble
Rectangle rc3 = rc;
rc3.Inflate(-15, -rc.Height / 3);
rc3.Y = rc3.Y - 2;
//rc3.Height = rc3.Height;
GraphicsPath path3 = GetPath(rc3, rc3.Height);
LinearGradientBrush br3 = new LinearGradientBrush(rc3, Color.FromArgb(255, Color.White), Color.FromArgb(0, Color.White), LinearGradientMode.Vertical);
itemImage = new Bitmap(this.Width - 2, _itemHeight);
Graphics g = Graphics.FromImage(itemImage);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.FillPath(br2, path2);
g.FillPath(br1, path1);
g.FillPath(br3, path3);
_imagesCache[color] = itemImage;
}
itemImage = _imagesCache[color];
return itemImage;
}
private void EnableDoubleBuffering()
{
//Debug.WriteLine("EnableDoubleBuffering");
// Set the value of the double-buffering style bits to true.
this.SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.SupportsTransparentBackColor,
true);
this.UpdateStyles();
}
public void Reset()
{
//Debug.WriteLine("Reset");
_queuedItems = new List<QueueUsageEntry>();
}
//public void Queue(string text, Color color, bool blink)
//{
// //Debug.WriteLine("Queue");
// _queuedItems.Add(new QueueUsageEntry(text, color, blink));
// //this.Invalidate();
//}
public void SetQueue(List<QueueUsageEntry> list)
{
//Debug.WriteLine("SetQueue");
bool invalidate = false;
if (_queuedItems.Count != list.Count)
{
invalidate = true;
}
else
{
int counter = Math.Min(list.Count, _maxItemsVisible);
for (int i = 0; i < counter; i++)
{
if (_queuedItems[i] != list[i])
{
invalidate = true;
break;
}
}
}
if (invalidate)
{
//Debug.WriteLine("_invalidate = true");
_queuedItems = list;
_invalidate = invalidate;
}
//_queuedItems = list;
//_queuedItems.Clear();
//foreach (QueueUsageEntry entry in list)
//{
// _queuedItems.Add(entry);
//}
//_invalidate = true;
//this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
//Debug.WriteLine("OnPaint");
Bitmap bitmap = new Bitmap(Width, Height);
Graphics g = Graphics.FromImage(bitmap);
g.FillPath(Brushes.White, _pathBorder);
int counter = Math.Min(_maxItemsVisible, _queuedItems.Count);
int i = 0;
foreach (QueueUsageEntry entry in _queuedItems)
{
if (i > counter)
{
break;
}
//int top = 0;
//int bottom = 0;
//if (topdown)
//{
// bottom = 1;
// top = bottom;
// top += i * _itemHeight;
// bottom += (i + 1) * _itemHeight;
//}
//else
//{
// bottom = this.Height - 1;
// top = bottom;
// bottom -= i * _itemHeight;
// top -= (i + 1) * _itemHeight;
//}
//g.DrawLine(Pens.Black, 0, top, this.Width, top);
string text = (entry.IsExecuting ? ">" : "") + entry.Text;
if (i == _lastVisibleItemIndex)
{
text = "(" + (_queuedItems.Count - _maxItemsVisible) + ")...";
}
SizeF size = g.MeasureString(entry.Text, this.Font);
//Debug.WriteLine(size.Width);
Bitmap itemImage = GetItemsImage(entry.Color);
RectangleF slot = _slots[i];
//g.DrawImage(itemImage, -1, top);
g.DrawImage(itemImage, -1, slot.Top-2);
//g.DrawString(text, this.Font, Brushes.Black, new RectangleF((this.Width - size.Width) / 2, top + 2, this.Width, bottom));
g.DrawString(text, this.Font, Brushes.Black, slot);
++i;
}
g.DrawPath(Pens.Black, _pathBorder);
//g.DrawRectangle(Pens.Black, border);
e.Graphics.DrawImage(bitmap, 0, 0);
}
private static GraphicsPath GetPath(Rectangle rc, int r)
{
//Debug.WriteLine("GetPath");
int x = rc.X, y = rc.Y, w = rc.Width, h = rc.Height;
GraphicsPath path = new GraphicsPath();
path.AddArc(x, y, r, r, 180, 90); //Upper left corner
path.AddArc(x + w - r, y, r, r, 270, 90); //Upper right corner
path.AddArc(x + w - r, y + h - r, r, r, 0, 90); //Lower right corner
path.AddArc(x, y + h - r, r, r, 90, 90); //Lower left corner
path.CloseFigure();
return path;
}
private void ControlRezised()
{
//Debug.WriteLine("ControlRezised");
Graphics g = Graphics.FromHwnd(this.Handle);
SizeF size = g.MeasureString("X", this.Font);
g.Dispose();
_itemHeight = (int)size.Height + 5;
_maxItemsVisible = this.Height / _itemHeight - 1;
_lastVisibleItemIndex = _maxItemsVisible;
_imagesCache = new Dictionary<Color, Bitmap>();
Rectangle border = new Rectangle(0, 0, this.ClientRectangle.Width - 1, this.ClientRectangle.Height - 1);
_pathBorder = GetPath(border, 20);
PrepareSlots();
}
private void PrepareSlots()
{
bool topdown = true;
_slots = new RectangleF[_maxItemsVisible+5];
for (int i = 0; i < _slots.Length; i++)
{
int top = 0;
int bottom = 0;
if (topdown)
{
bottom = 1;
top = bottom;
top += i * _itemHeight;
bottom += (i + 1) * _itemHeight;
}
else
{
bottom = this.Height - 1;
top = bottom;
bottom -= i * _itemHeight;
top -= (i + 1) * _itemHeight;
}
_slots[i] = new RectangleF((this.Width - 55) / 2, top + 2, this.Width, bottom);
}
}
private void QueueUsageControl_Resize(object sender, EventArgs e)
{
//Debug.WriteLine("QueueUsageControl_Resize");
ControlRezised();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (_invalidate)
{
_invalidate = false;
}
Invalidate();
}
}
}
+123
View File
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
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">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</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 for serialized 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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<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" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</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>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>
+49
View File
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace UsageControl
{
public partial class QueueUsageControl
{
public class QueueUsageEntry
{
private string _text;
private Color _color;
private bool _isExecuting;
public QueueUsageEntry(
string text,
Color color) : this (text, color, false)
{
}
public QueueUsageEntry(
string text,
Color color,
bool blink)
{
_text = text;
_color = color;
_isExecuting = blink;
}
public Color Color
{
get { return _color; }
}
public string Text
{
get { return _text; }
}
public bool IsExecuting
{
get { return _isExecuting; }
set { _isExecuting = value; }
}
}
}
}
+33
View File
@@ -73,6 +73,16 @@
<DebugType>none</DebugType>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseCE|AnyCPU' ">
<OutputPath>bin\ReleaseCE\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<BaseAddress>285212672</BaseAddress>
<Optimize>true</Optimize>
<DebugType>
</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System">
<Name>System</Name>
@@ -94,12 +104,35 @@
<Compile Include="AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="QueueUsageControl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="QueueUsageControl.Designer.cs">
<DependentUpon>QueueUsageControl.cs</DependentUpon>
</Compile>
<Compile Include="QueueUsageEntry.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="UsageControl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="UsageHistoryControl.cs">
<SubType>UserControl</SubType>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<SubType>Designer</SubType>
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="QueueUsageControl.resx">
<SubType>Designer</SubType>
<DependentUpon>QueueUsageControl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="UsageControl.resx">
<DependentUpon>UsageControl.cs</DependentUpon>
<SubType>Designer</SubType>
File diff suppressed because it is too large Load Diff
+372
View File
@@ -0,0 +1,372 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using UsageControl;
using Amib.Threading;
using System.Threading;
using System.Collections;
namespace WorkItemsGroupDemo
{
public partial class Form1 : Form
{
private bool _running = false;
private bool _paused = false;
private bool _advancedMode = false;
private int _workItemsGenerated;
Hashtable _workingStates = Hashtable.Synchronized(new Hashtable());
private SmartThreadPool _stp;
private IWorkItemsGroup _wig1;
private IWorkItemsGroup _wig2;
private IWorkItemsGroup _wig3;
private int[] _lastIndex = new int[4];
private static readonly Color _stpColor = Color.Gray;
private static readonly Color _wig1Color = Color.Red;
private static readonly Color _wig2Color = Color.Green;
private static readonly Color _wig3Color = Color.Blue;
private class WigEntry
{
public IWorkItemsGroup _wig;
public QueueUsageControl _queueUsageControl;
public Label _isIdle;
public WigEntry(
IWorkItemsGroup wig,
QueueUsageControl queueUsageControl,
Label isIdle)
{
_wig = wig;
_queueUsageControl = queueUsageControl;
_isIdle = isIdle;
}
}
private WigEntry[] _wigEntries = null;
public Form1()
{
InitializeComponent();
InitSTP();
UpdateControls(false);
UpdateModeControls();
}
private void InitSTP()
{
STPStartInfo stpStartInfo = new STPStartInfo();
stpStartInfo.StartSuspended = true;
stpStartInfo.MaxWorkerThreads = (int)spinCon6.Value;
stpStartInfo.IdleTimeout = 5000;
stpStartInfo.PerformanceCounterInstanceName = "SmartThreadPoolDemo";
_stp = new SmartThreadPool(stpStartInfo);
_wig1 = _stp.CreateWorkItemsGroup((int)spinCon1.Value);
_wig2 = _stp.CreateWorkItemsGroup((int)spinCon2.Value);
_wig3 = _stp.CreateWorkItemsGroup((int)spinCon3.Value);
spinCon1.Tag = _wig1;
spinCon2.Tag = _wig2;
spinCon3.Tag = _wig3;
spinCon6.Tag = _stp;
comboWIPriority1.SelectedIndex = 1;
comboWIPriority2.SelectedIndex = 1;
comboWIPriority3.SelectedIndex = 1;
comboWIPriority6.SelectedIndex = 1;
_wigEntries = new WigEntry[]
{
new WigEntry(_wig1, queueUsageControl1, lblStatus1),
new WigEntry(_wig2, queueUsageControl2, lblStatus2),
new WigEntry(_wig3, queueUsageControl3, lblStatus3),
};
for (int i = 0; i < _lastIndex.Length; i++)
{
_lastIndex[i] = 1;
}
}
private void btnStart_Click(object sender, EventArgs e)
{
_running = !_running;
btnStart.Text = _running ? "Stop STP" : "Start STP";
if (_running)
{
Start();
}
else
{
Shutdown();
}
}
private void Start()
{
_workItemsGenerated = 0;
UpdateControls(true);
_stp.Start();
_wig1.Start();
_wig2.Start();
_wig3.Start();
}
private void Shutdown()
{
_stp.Shutdown(false, 2000);
InitSTP();
UpdateControls(false);
}
private void UpdateControls(bool start)
{
timerPoll.Enabled = start;
lblThreadInUse.Text = "0";
lblThreadsInPool.Text = "0";
lblWaitingCallbacks.Text = "0";
usageThreadsInPool.Value1 = 0;
usageThreadsInPool.Value2 = 0;
lblWorkItemsCompleted.Text = "0";
lblWorkItemsGenerated.Text = "0";
usageHistorySTP.Reset();
usageHistorySTP.Maximum = usageThreadsInPool.Maximum;
spinIdleTimeout.Enabled = !start;
}
private object DoNothing(object state)
{
WorkItemState workItemState = (WorkItemState)state;
_workingStates.Add(workItemState.QueueUsageEntry, workItemState.QueueUsageEntry);
do
{
if (SmartThreadPool.IsWorkItemCanceled)
{
break;
}
Thread.Sleep(workItemState.SleepDuration);
} while (_paused);
_workingStates.Remove(workItemState.QueueUsageEntry);
return null;
}
private void timer1_Tick(object sender, EventArgs e)
{
foreach (WigEntry wigEntry in _wigEntries)
{
UpdateQueueUsageControl(
wigEntry._wig,
wigEntry._queueUsageControl,
wigEntry._isIdle);
}
UpdateWorkingSet();
}
private void UpdateWorkingSet()
{
lblStatus6.Text = _stp.IsIdle ? "Idle" : "Working";
object [] statesWorking = null;
lock (_workingStates.SyncRoot)
{
statesWorking = new object[_workingStates.Count];
_workingStates.Keys.CopyTo(statesWorking, 0);
}
object[] statesSTP = _stp.GetStates();
List<QueueUsageControl.QueueUsageEntry> list = new List<QueueUsageControl.QueueUsageEntry>();
foreach (QueueUsageControl.QueueUsageEntry entry in statesWorking)
{
if (null != entry)
{
entry.IsExecuting = true;
list.Add(entry);
}
}
foreach (WorkItemState state in statesSTP)
{
if (null != state)
{
list.Add(state.QueueUsageEntry);
}
}
queueUsageControl6.SetQueue(list);
}
private void UpdateQueueUsageControl(
IWorkItemsGroup wig,
QueueUsageControl queueUsageControl,
Label label)
{
label.Text = wig.IsIdle ? "Idle" : "Working";
object[] states = wig.GetStates();
List<QueueUsageControl.QueueUsageEntry> list = new List<QueueUsageControl.QueueUsageEntry>();
foreach (WorkItemState state in states)
{
if (null != state)
{
list.Add(state.QueueUsageEntry);
}
}
queueUsageControl.SetQueue(list);
}
private void btnPause_Click(object sender, EventArgs e)
{
_paused = !_paused;
btnPause.Text = _paused ? "Resume STP" : "Pause STP";
}
#region Test functions
private void btnState1_Click(object sender, EventArgs e)
{
List<QueueUsageControl.QueueUsageEntry> list = new List<QueueUsageControl.QueueUsageEntry>();
list.Add(new QueueUsageControl.QueueUsageEntry("#A", Color.Yellow));
list.Add(new QueueUsageControl.QueueUsageEntry("#B", Color.Green));
list.Add(new QueueUsageControl.QueueUsageEntry("#C", Color.Black));
list.Add(new QueueUsageControl.QueueUsageEntry("#D", Color.HotPink));
queueUsageControl1.SetQueue(list);
}
private void btnState2_Click(object sender, EventArgs e)
{
List<QueueUsageControl.QueueUsageEntry> list = new List<QueueUsageControl.QueueUsageEntry>();
list.Add(new QueueUsageControl.QueueUsageEntry("#1", Color.Cyan));
list.Add(new QueueUsageControl.QueueUsageEntry("#2", Color.Magenta));
list.Add(new QueueUsageControl.QueueUsageEntry("#3", Color.Red));
queueUsageControl1.SetQueue(list);
}
#endregion
#region WorkItemState class
private class WorkItemState
{
public readonly QueueUsageControl.QueueUsageEntry QueueUsageEntry;
public readonly int SleepDuration;
public WorkItemState(
QueueUsageControl.QueueUsageEntry queueUsageEntry,
int sleepDuration)
{
QueueUsageEntry = queueUsageEntry;
SleepDuration = sleepDuration;
}
}
#endregion
private void EnqueueWorkItems(ref int startIndex, int count, string text, Color color, WorkItemPriority priority, IWorkItemsGroup wig, int sleepDuration)
{
for (int i = 0; i < count; ++i, ++startIndex)
{
wig.QueueWorkItem(
DoNothing,
new WorkItemState(new QueueUsageControl.QueueUsageEntry(string.Format("{0}{1} ({2})", text, startIndex, priority.ToString().Substring(0,2 )), color), sleepDuration),
priority);
}
_workItemsGenerated += count;
}
private void btnCancel1_Click(object sender, EventArgs e)
{
_wig1.Cancel();
}
private void btnCancel2_Click(object sender, EventArgs e)
{
_wig2.Cancel();
}
private void btnCancel3_Click(object sender, EventArgs e)
{
_wig3.Cancel();
}
private void btnCancel6_Click(object sender, EventArgs e)
{
_stp.Cancel();
}
private void spinCon_ValueChanged(object sender, EventArgs e)
{
NumericUpDown spin = sender as NumericUpDown;
IWorkItemsGroup wig = spin.Tag as IWorkItemsGroup;
wig.Concurrency = (int)spin.Value;
}
private void timer2_Tick(object sender, EventArgs e)
{
EnqueueWorkItems(ref _lastIndex[0], Convert.ToInt32(spinProduction1.Value), "#", _wig1Color, (WorkItemPriority)(2 * comboWIPriority1.SelectedIndex), _wig1, Convert.ToInt32(spinDuration1.Value));
EnqueueWorkItems(ref _lastIndex[1], Convert.ToInt32(spinProduction2.Value), "#", _wig2Color, (WorkItemPriority)(2 * comboWIPriority2.SelectedIndex), _wig2, Convert.ToInt32(spinDuration2.Value));
EnqueueWorkItems(ref _lastIndex[2], Convert.ToInt32(spinProduction3.Value), "#", _wig3Color, (WorkItemPriority)(2 * comboWIPriority3.SelectedIndex), _wig3, Convert.ToInt32(spinDuration3.Value));
EnqueueWorkItems(ref _lastIndex[3], Convert.ToInt32(spinProduction6.Value), "#", _stpColor, (WorkItemPriority)(2 * comboWIPriority6.SelectedIndex), _stp, Convert.ToInt32(spinDuration6.Value));
}
private void btnMode_Click(object sender, EventArgs e)
{
_advancedMode = !_advancedMode;
UpdateModeControls();
}
private void UpdateModeControls()
{
btnMode.Text = _advancedMode ? "Basic <<" : "Advanced >>";
panelWIGsCtrls.Visible = _advancedMode;
groupWIGQueues.Visible = _advancedMode;
}
private void timerPoll_Tick(object sender, EventArgs e)
{
SmartThreadPool stp = _stp;
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 Form1_Load(object sender, EventArgs e)
{
label5.Image = QueueUsageControl.GenerateItemImage("", _wig1Color, 72, label5.Height, label5.Font); ;
label4.Image = QueueUsageControl.GenerateItemImage("", _wig2Color, 72, label5.Height, label5.Font); ;
label3.Image = QueueUsageControl.GenerateItemImage("", _wig3Color, 72, label5.Height, label5.Font); ;
label8.Image = QueueUsageControl.GenerateItemImage("", _stpColor, 72, label5.Height, label5.Font); ;
}
}
}
+150
View File
@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
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">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</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 for serialized 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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<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" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</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>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>94, 4</value>
</metadata>
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 7</value>
</metadata>
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>94, 4</value>
</metadata>
<metadata name="timer2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>186, 4</value>
</metadata>
<metadata name="pcActiveThreads.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 54</value>
</metadata>
<metadata name="pcInUseThreads.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>150, 54</value>
</metadata>
<metadata name="pcQueuedWorkItems.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>282, 54</value>
</metadata>
<metadata name="pcCompletedWorkItems.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>438, 54</value>
</metadata>
<metadata name="timerPoll.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>609, 54</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>25</value>
</metadata>
</root>
+20
View File
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace WorkItemsGroupDemo
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
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("WindowsApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WindowsApplication1")]
[assembly: AssemblyCopyright("Copyright © 2006")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("68872ba4-6524-406b-9c96-cf8ca3f4c729")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+63
View File
@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.832
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WorkItemsGroupDemo.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WorkItemsGroupDemo.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
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">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</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 for serialized 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="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<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>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+26
View File
@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.832
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WorkItemsGroupDemo.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
@@ -0,0 +1,99 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{DC005A64-FAE9-4CFA-ADC8-F1D1FE7FE6CD}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WorkItemsGroupDemo</RootNamespace>
<AssemblyName>WorkItemsGroupDemo</AssemblyName>
<StartupObject>WorkItemsGroupDemo.Program</StartupObject>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseCE|AnyCPU' ">
<OutputPath>bin\ReleaseCE\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Form1.resx">
<SubType>Designer</SubType>
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SmartThreadPool\SmartThreadPool.csproj">
<Project>{8684FC56-A679-4E2E-8F96-E172FB062EB6}</Project>
<Name>SmartThreadPool</Name>
</ProjectReference>
<ProjectReference Include="..\UsageControl\UsageControl.csproj">
<Project>{C11A4561-CCB5-4C96-8DF2-B804031D89D8}</Project>
<Name>UsageControl</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>