mirror of
https://github.com/farcasclaudiu/SmartThreadPool.git
synced 2026-06-22 07:01:18 +03:00
v2.0
SmartThreadPool v2.0
This commit is contained in:
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 |
Generated
+316
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 1.3
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">1.3</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1">this is my long string</data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
[base64 mime encoded serialized .NET Framework object]
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
[base64 mime encoded string representing a byte array form of the .NET Framework object]
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used forserialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>1.3</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name="$this.Locked" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name="$this.SnapToGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="$this.DrawGrid" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="$this.TrayHeight" type="System.Int32, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>80</value>
|
||||
</data>
|
||||
<data name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>(Default)</value>
|
||||
</data>
|
||||
<data name="$this.Localizable" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name="$this.Name">
|
||||
<value>UsageControl</value>
|
||||
</data>
|
||||
<data name="$this.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>Private</value>
|
||||
</data>
|
||||
<data name="$this.GridSize" type="System.Drawing.Size, System.Drawing, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>8, 8</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using NUnit.Framework;
|
||||
|
||||
using Amib.Threading;
|
||||
|
||||
namespace SmartThreadPoolTests
|
||||
namespace WorkItemsGroupTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for TestWIGConcurrency.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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("")]
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+612
-478
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
+503
-487
File diff suppressed because it is too large
Load Diff
+46
-370
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
Generated
+1269
File diff suppressed because it is too large
Load Diff
@@ -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); ;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
@@ -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>
|
||||
Reference in New Issue
Block a user