mirror of
https://github.com/AlexMacocian/SystemExtensions.git
synced 2026-07-22 09:09:30 +00:00
Implemented Treap and Treap tests.
This commit is contained in:
@@ -7,8 +7,9 @@ using System.Threading.Tasks;
|
||||
namespace SystemExtensions.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Binary heap implementation
|
||||
/// Binary heap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
public class BinaryHeap<T>
|
||||
{
|
||||
#region Fields
|
||||
@@ -17,6 +18,9 @@ namespace SystemExtensions.Collections
|
||||
int capacity, count, initialCapacity;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Minimum value from the heap.
|
||||
/// </summary>
|
||||
public T Min
|
||||
{
|
||||
get
|
||||
@@ -24,6 +28,9 @@ namespace SystemExtensions.Collections
|
||||
return items[1];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Maximum value from the heap.
|
||||
/// </summary>
|
||||
public T Max
|
||||
{
|
||||
get
|
||||
@@ -31,6 +38,9 @@ namespace SystemExtensions.Collections
|
||||
return items[count];
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Capacity of the heap.
|
||||
/// </summary>
|
||||
public int Capacity { get => capacity;
|
||||
set
|
||||
{
|
||||
@@ -41,9 +51,16 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Number of elements in the heap.
|
||||
/// </summary>
|
||||
public int Count { get => count; }
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="comparator">Function used to compare the elements.</param>
|
||||
public BinaryHeap(Comparison<T> comparator)
|
||||
{
|
||||
capacity = 10;
|
||||
@@ -51,6 +68,11 @@ namespace SystemExtensions.Collections
|
||||
items = new T[capacity];
|
||||
this.comparator = comparator;
|
||||
}
|
||||
/// <summary>
|
||||
/// Constructor for a binary heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="comparator">Function used to compare the elements.</param>
|
||||
/// <param name="capacity">Initial capacity of the heap. Used for initial alocation of the array.</param>
|
||||
public BinaryHeap(Comparison<T> comparator, int capacity)
|
||||
{
|
||||
this.capacity = capacity;
|
||||
|
||||
@@ -6,6 +6,10 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Fibonacci Heap implementation. Implements IDisposable to clear the sub structure of the heap.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type</typeparam>
|
||||
public class FibonacciHeap<T> : IDisposable
|
||||
{
|
||||
#region Fields
|
||||
@@ -36,6 +40,10 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for Fibonacci heap data structure.
|
||||
/// </summary>
|
||||
/// <param name="comparator">Function used to compare the elements.</param>
|
||||
public FibonacciHeap(Comparison<T> comparator)
|
||||
{
|
||||
this.comparator = comparator;
|
||||
@@ -100,7 +108,7 @@ namespace SystemExtensions.Collections
|
||||
/// <summary>
|
||||
/// Determines whether the heap contains a specified value.
|
||||
/// </summary>
|
||||
/// <param name="value">Valye to locate in the heap.</param>
|
||||
/// <param name="value">Value to locate in the heap.</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
@@ -418,6 +426,10 @@ namespace SystemExtensions.Collections
|
||||
#endregion
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false;
|
||||
/// <summary>
|
||||
/// Disposes of the contents of the heap. Called by the public Dispose().
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
@@ -435,6 +447,9 @@ namespace SystemExtensions.Collections
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Disposes of the contents of the heap.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
|
||||
@@ -6,13 +6,20 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Priority Queue data structure. The implementation is based on an array-based implementation of Binary Heap.
|
||||
/// Exposes some of the functionality of the Binary Heap as a queue.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
public class PriorityQueue<T>
|
||||
{
|
||||
#region Fields
|
||||
private BinaryHeap<T> binaryHeap;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Returns the number of elements stored into the queue.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
@@ -21,20 +28,29 @@ namespace SystemExtensions.Collections
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for priority queue data structure.
|
||||
/// </summary>
|
||||
/// <param name="comparator">Function used to compare the elements.</param>
|
||||
public PriorityQueue(Comparison<T> comparator)
|
||||
{
|
||||
binaryHeap = new BinaryHeap<T>(comparator);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Add provided value to the queue.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be added to the queue.</param>
|
||||
public void Enqueue(T value)
|
||||
{
|
||||
binaryHeap.Insert(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pops the queue and removes the highest priority value from the queue.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue</returns>
|
||||
public T Dequeue()
|
||||
{
|
||||
if (Count > 0)
|
||||
@@ -46,18 +62,22 @@ namespace SystemExtensions.Collections
|
||||
throw new IndexOutOfRangeException("Queue is empty!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up the highest priority value from the queue. Doesn't alter the queue in any way.
|
||||
/// </summary>
|
||||
/// <returns>Highest priority value from the queue.</returns>
|
||||
public T Peek()
|
||||
{
|
||||
return binaryHeap.Min;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the queue contents, removing any value stored into the queue.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
binaryHeap.Clear();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Treap implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Provided type.</typeparam>
|
||||
public class Treap<T>
|
||||
{
|
||||
#region Fields
|
||||
private Random randomGen;
|
||||
private Item<T> root;
|
||||
private Comparison<T> comparator;
|
||||
private int count;
|
||||
#endregion
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Count of values in the treap.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return count;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor for treap.
|
||||
/// </summary>
|
||||
/// <param name="comparator">Comparator method used to compare values.</param>
|
||||
public Treap(Comparison<T> comparator)
|
||||
{
|
||||
randomGen = new Random();
|
||||
this.comparator = comparator;
|
||||
}
|
||||
#endregion
|
||||
#region Private Methods
|
||||
private Item<T> InsertNode(Item<T> node, T key)
|
||||
{
|
||||
if(node == null) {
|
||||
node = new Item<T>(key, randomGen.Next(0, 100));
|
||||
return node;
|
||||
}
|
||||
else if (comparator(key, node.Key) <= 0)
|
||||
{
|
||||
node.Left = InsertNode(node.Left, key);
|
||||
if(node.Left.Priority > node.Priority)
|
||||
{
|
||||
node = RotateRight(node);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Right = InsertNode(node.Right, key);
|
||||
if(node.Right.Priority > node.Priority)
|
||||
{
|
||||
node = RotateLeft(node);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
private Item<T> RemoveNode(Item<T> node, T key)
|
||||
{
|
||||
if(node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
if(comparator.Invoke(key, node.Key) < 0)
|
||||
{
|
||||
node.Left = RemoveNode(node.Left, key);
|
||||
}
|
||||
else if(comparator.Invoke(key, node.Key) > 0)
|
||||
{
|
||||
node.Right = RemoveNode(node.Right, key);
|
||||
}
|
||||
else if (node.Left == null)
|
||||
{
|
||||
node = node.Right;
|
||||
}
|
||||
else if(node.Right == null)
|
||||
{
|
||||
node = node.Left;
|
||||
}
|
||||
else if(node.Left.Priority < node.Right.Priority)
|
||||
{
|
||||
node = RotateLeft(node);
|
||||
node.Left = RemoveNode(node.Left, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = RotateRight(node);
|
||||
node.Right = RemoveNode(node.Right, key);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
private Item<T> RotateRight(Item<T> node)
|
||||
{
|
||||
Item<T> temp = node.Left, temp2 = temp.Right;
|
||||
temp.Right = node;
|
||||
node.Left = temp2;
|
||||
return temp;
|
||||
}
|
||||
private Item<T> RotateLeft(Item<T> node)
|
||||
{
|
||||
Item<T> temp = node.Right, temp2 = temp.Left;
|
||||
temp.Left = node;
|
||||
node.Right = temp2;
|
||||
return temp;
|
||||
}
|
||||
private void Clear(Item<T> node)
|
||||
{
|
||||
if(node.Left != null)
|
||||
{
|
||||
Clear(node.Left);
|
||||
}
|
||||
if(node.Right != null)
|
||||
{
|
||||
Clear(node.Right);
|
||||
}
|
||||
node.Left = node.Right = null;
|
||||
}
|
||||
private Item<T> Find(Item<T> node, T key)
|
||||
{
|
||||
if(node == null)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(comparator.Invoke(node.Key, key) < 0)
|
||||
{
|
||||
Item<T> found = Find(node.Left, key);
|
||||
if(found == null)
|
||||
{
|
||||
found = Find(node.Right, key);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else if(comparator.Invoke(node.Key, key) > 0)
|
||||
{
|
||||
Item<T> found = Find(node.Right, key);
|
||||
if (found == null)
|
||||
{
|
||||
found = Find(node.Left, key);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else
|
||||
{
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void ToArray(Item<T> node, ref T[] array, ref int index)
|
||||
{
|
||||
if(node != null)
|
||||
{
|
||||
ToArray(node.Left, ref array, ref index);
|
||||
array[index] = node.Key;
|
||||
index++;
|
||||
ToArray(node.Right, ref array, ref index);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Inserts value into treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be inserted.</param>
|
||||
public void Insert(T value)
|
||||
{
|
||||
root = InsertNode(root, value);
|
||||
count++;
|
||||
}
|
||||
/// <summary>
|
||||
/// Removes value from treap.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to be removed.</param>
|
||||
public void Remove(T value)
|
||||
{
|
||||
root = RemoveNode(root, value);
|
||||
count--;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears the treap.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
Clear(root);
|
||||
root = null;
|
||||
count = 0;
|
||||
}
|
||||
/// <summary>
|
||||
/// Determines whether the treap contains the specified value.
|
||||
/// </summary>
|
||||
/// <param name="value">Value to locate in the treap.</param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T value)
|
||||
{
|
||||
return Find(root, value) != null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the treap structure as an ordered array.
|
||||
/// </summary>
|
||||
/// <returns>Ordered array containing the values stored in the treap.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
if(root != null)
|
||||
{
|
||||
T[] array = new T[count];
|
||||
int index = 0;
|
||||
ToArray(root, ref array, ref index);
|
||||
return array;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal class Item<T>
|
||||
{
|
||||
public T Key;
|
||||
public int Priority;
|
||||
public Item<T> Left, Right;
|
||||
public Item(T key, int priority)
|
||||
{
|
||||
Key = key;
|
||||
Priority = priority;
|
||||
Left = null;
|
||||
Right = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class containing implementation of comparators to be used when creating and using collections.
|
||||
/// </summary>
|
||||
public static class Comparators
|
||||
{
|
||||
#region Fields
|
||||
|
||||
@@ -5,11 +5,11 @@ 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("PriorityThreadPool")]
|
||||
[assembly: AssemblyTitle("SystemExtensions")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("PriorityThreadPool")]
|
||||
[assembly: AssemblyProduct("SystemExtensions")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
<ProjectGuid>{55850FF3-70E4-4828-BEEE-39837AC0D24C}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>PriorityThreadPool</RootNamespace>
|
||||
<AssemblyName>PriorityThreadPool</AssemblyName>
|
||||
<RootNamespace>SystemExtensions</RootNamespace>
|
||||
<AssemblyName>SystemExtensions</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -21,6 +22,8 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Debug\SystemExtensions.xml</DocumentationFile>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
@@ -29,6 +32,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@@ -44,6 +48,7 @@
|
||||
<Compile Include="Collections\BinaryHeap.cs" />
|
||||
<Compile Include="Collections\FibonacciHeap.cs" />
|
||||
<Compile Include="Collections\PriorityQueue.cs" />
|
||||
<Compile Include="Collections\Treap.cs" />
|
||||
<Compile Include="Comparators.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Threading\PriorityThreadPool.cs" />
|
||||
|
||||
@@ -8,6 +8,11 @@ using SystemExtensions.Collections;
|
||||
|
||||
namespace SystemExtensions.Threading
|
||||
{
|
||||
/// <summary>
|
||||
/// Threadpool implementation that uses a priority queue as the queue for the tasks to execute.
|
||||
/// Features both an automated algorithm to calibrate the number of active threads and a Constructor for constructing
|
||||
/// a threadpool manually, without the auto-managed pool algorithm.
|
||||
/// </summary>
|
||||
public class PriorityThreadPool : IDisposable
|
||||
{
|
||||
#region Enum
|
||||
@@ -16,10 +21,25 @@ namespace SystemExtensions.Threading
|
||||
/// </summary>
|
||||
public enum TaskPriority
|
||||
{
|
||||
/// <summary>
|
||||
/// Highest priority of a task.
|
||||
/// </summary>
|
||||
Highest,
|
||||
/// <summary>
|
||||
/// Priority level above the default level.
|
||||
/// </summary>
|
||||
AboveNormal,
|
||||
/// <summary>
|
||||
/// Default priority level of all tasks without a specified priority level.
|
||||
/// </summary>
|
||||
Normal,
|
||||
/// <summary>
|
||||
/// Priority level below the default level.
|
||||
/// </summary>
|
||||
BelowNormal,
|
||||
/// <summary>
|
||||
/// Lowest priority level.
|
||||
/// </summary>
|
||||
Lowest
|
||||
}
|
||||
#endregion
|
||||
@@ -27,8 +47,8 @@ namespace SystemExtensions.Threading
|
||||
/// <summary>
|
||||
/// List that contains current running threads and their status.
|
||||
/// </summary>
|
||||
private List<WorkerThread> threadpool;
|
||||
private PriorityQueue<Tuple<TaskPriority, WaitCallback, object>> tasks;
|
||||
private volatile List<WorkerThread> threadpool;
|
||||
private volatile PriorityQueue<Tuple<TaskPriority, WaitCallback, object>> tasks;
|
||||
private Thread observer;
|
||||
private int maxThreads;
|
||||
private object tasksLock = new object();
|
||||
@@ -37,9 +57,18 @@ namespace SystemExtensions.Threading
|
||||
public Thread thread;
|
||||
public bool running, working;
|
||||
}
|
||||
private struct Statistics
|
||||
{
|
||||
public bool Initialized;
|
||||
public int PerformanceCounter;
|
||||
public DateTime LastUpdate;
|
||||
public double LoopFrequency;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Returns the number of active threads in the threadpool.
|
||||
/// </summary>
|
||||
public int NumberOfThreads
|
||||
{
|
||||
get
|
||||
@@ -47,8 +76,31 @@ namespace SystemExtensions.Threading
|
||||
return threadpool.Count;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns true if there are no tasks queued.
|
||||
/// </summary>
|
||||
public bool Empty
|
||||
{
|
||||
get
|
||||
{
|
||||
return tasks.Count == 0;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Maximum amount of threads that the pool can utilize
|
||||
/// </summary>
|
||||
public int MaxThreads
|
||||
{
|
||||
set
|
||||
{
|
||||
maxThreads = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
return maxThreads;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
/// <summary>
|
||||
/// Constructor that initializes a threadpool using default values. All threads run at the same priority.
|
||||
@@ -58,16 +110,16 @@ namespace SystemExtensions.Threading
|
||||
{
|
||||
threadpool = new List<WorkerThread>();
|
||||
tasks = new PriorityQueue<Tuple<TaskPriority, WaitCallback, object>>(PriorityCompare);
|
||||
int nrThreads = (int)Math.Ceiling((double)System.Environment.ProcessorCount / 4);
|
||||
maxThreads = System.Environment.ProcessorCount;
|
||||
for (int i = 0; i < nrThreads; i++)
|
||||
for (int i = 0; i < maxThreads; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(worker);
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
@@ -75,7 +127,8 @@ namespace SystemExtensions.Threading
|
||||
{
|
||||
ObserverLoop();
|
||||
});
|
||||
observer.Priority = ThreadPriority.Normal;
|
||||
observer.Name = "ThreadPool ObserverThread";
|
||||
observer.Priority = ThreadPriority.BelowNormal;
|
||||
observer.Start();
|
||||
}
|
||||
/// <summary>
|
||||
@@ -87,15 +140,15 @@ namespace SystemExtensions.Threading
|
||||
threadpool = new List<WorkerThread>();
|
||||
tasks = new PriorityQueue<Tuple<TaskPriority, WaitCallback, object>>(PriorityCompare);
|
||||
this.maxThreads = Math.Max(maxThreads, 1);
|
||||
int nrThreads = (int)Math.Ceiling((double)this.maxThreads / 4);
|
||||
for (int i = 0; i < nrThreads; i++)
|
||||
for (int i = 0; i < maxThreads; i++)
|
||||
{
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(worker);
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
@@ -103,7 +156,8 @@ namespace SystemExtensions.Threading
|
||||
{
|
||||
ObserverLoop();
|
||||
});
|
||||
observer.Priority = ThreadPriority.Normal;
|
||||
observer.Name = "ThreadPool ObserverThread";
|
||||
observer.Priority = ThreadPriority.BelowNormal;
|
||||
observer.Start();
|
||||
}
|
||||
/// <summary>
|
||||
@@ -124,10 +178,11 @@ namespace SystemExtensions.Threading
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(worker);
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.Lowest;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
@@ -136,10 +191,11 @@ namespace SystemExtensions.Threading
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(worker);
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.BelowNormal;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
@@ -148,10 +204,11 @@ namespace SystemExtensions.Threading
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(worker);
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.Normal;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
@@ -160,10 +217,11 @@ namespace SystemExtensions.Threading
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(worker);
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.AboveNormal;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
@@ -172,30 +230,39 @@ namespace SystemExtensions.Threading
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(worker);
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.thread.Priority = ThreadPriority.Highest;
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Add a work item into the queue.
|
||||
/// </summary>
|
||||
/// <param name="waitCallback">WaitCallBack delegate that will be invoked by the threads.</param>
|
||||
/// <param name="callbackState">State used as parameter during invoke.</param>
|
||||
/// <param name="taskPriority">Priority of task. Affects its position into the queue.</param>
|
||||
public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState, TaskPriority taskPriority)
|
||||
{
|
||||
while (!Monitor.TryEnter(tasksLock));
|
||||
tasks.Enqueue(new Tuple<TaskPriority, WaitCallback, object>(taskPriority, waitCallback, callbackState));
|
||||
Monitor.Exit(tasksLock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a work item into the queue.
|
||||
/// </summary>
|
||||
/// <param name="waitCallback">WaitCallBack delegate that will be invoked by the threads.</param>
|
||||
/// <param name="callbackState">State used as parameter during invoke.</param>
|
||||
public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState)
|
||||
{
|
||||
QueueUserWorkItem(waitCallback, callbackState, TaskPriority.Normal);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Function that compares two tasks based on their priorities
|
||||
@@ -259,7 +326,7 @@ namespace SystemExtensions.Threading
|
||||
/// Main loop that a thread from the pool is running.
|
||||
/// </summary>
|
||||
/// <threadId>Id of thread</threadId>
|
||||
private void ThreadMainLoop(WorkerThread thisWorkerThread)
|
||||
private void ThreadMainLoop(ref WorkerThread thisWorkerThread)
|
||||
{
|
||||
thisWorkerThread.running = true;
|
||||
while (thisWorkerThread.running)
|
||||
@@ -282,6 +349,7 @@ namespace SystemExtensions.Threading
|
||||
Monitor.Exit(tasksLock);
|
||||
if (task != null)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.Name + " - Running task!");
|
||||
WaitCallback waitCallback = task.Item2;
|
||||
waitCallback.Invoke(task.Item3);
|
||||
}
|
||||
@@ -294,84 +362,224 @@ namespace SystemExtensions.Threading
|
||||
/// </summary>
|
||||
private void ObserverLoop()
|
||||
{
|
||||
int counter = 0;
|
||||
Statistics statistics = new Statistics();
|
||||
while (true)
|
||||
{
|
||||
//Observer operates on a 100ms loop.
|
||||
//Observer operates on a 100ms loop. Due to the low priority of the thread itself, this loop will almost always take
|
||||
//considerably longer than 100ms.
|
||||
//Checks if the queue is empty. If yes, counter is decremented, else, counter is incremented.
|
||||
//If counter exceeds 5, it will try to add another thread to the thread, unless the threadpool has reached max size.
|
||||
//If counter is under -10, it will try to remove a thread from the threadpool, unless the threadpool has reached less than
|
||||
//max size / 4.
|
||||
Thread.Sleep(100);
|
||||
if(tasks.Count > 0)
|
||||
|
||||
//This part of code updates the statistics of the threadpool.
|
||||
if (statistics.Initialized)
|
||||
{
|
||||
counter++;
|
||||
if(counter > 5)
|
||||
double loopDuration = (DateTime.Now - statistics.LastUpdate).TotalMilliseconds;
|
||||
if(statistics.LoopFrequency == 0)
|
||||
{
|
||||
counter = 5;
|
||||
statistics.LoopFrequency = loopDuration;
|
||||
}
|
||||
else
|
||||
{
|
||||
statistics.LoopFrequency = (statistics.LoopFrequency + loopDuration) / 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
counter--;
|
||||
if(counter < -10)
|
||||
{
|
||||
counter = -10;
|
||||
}
|
||||
statistics.Initialized = true;
|
||||
}
|
||||
if(counter >= 5 && threadpool.Count < this.maxThreads)
|
||||
statistics.LastUpdate = DateTime.Now;
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
|
||||
//This part of code adjusts the performance counter. Ideally, the value should be 0.
|
||||
if(tasks.Count > 0)
|
||||
{
|
||||
//Add a thread to the threadpool.
|
||||
//Reset counter to 0.
|
||||
counter = 0;
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
statistics.PerformanceCounter++;
|
||||
if(statistics.PerformanceCounter > 5)
|
||||
{
|
||||
ThreadMainLoop(worker);
|
||||
});
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
statistics.PerformanceCounter = 5;
|
||||
}
|
||||
}
|
||||
if(counter <= -10 && threadpool.Count > maxThreads / 4)
|
||||
else
|
||||
{
|
||||
//Remove the last thread in the threadpool.
|
||||
//If thread is currently working, notify it to close.
|
||||
//Else, abort the thread.
|
||||
//Reset counter to 0.
|
||||
WorkerThread worker = threadpool[threadpool.Count - 1];
|
||||
threadpool.RemoveAt(threadpool.Count - 1);
|
||||
if (worker.working)
|
||||
statistics.PerformanceCounter--;
|
||||
if(statistics.PerformanceCounter < -10)
|
||||
{
|
||||
worker.running = false;
|
||||
statistics.PerformanceCounter = -10;
|
||||
}
|
||||
else
|
||||
{
|
||||
worker.thread.Abort();
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
//This part of code adjusts thread priorities based on the current performance of the threadpool
|
||||
if(tasks.Count > 0)
|
||||
{
|
||||
//If there are tasks pending, find a thread with priority under Normal and upgrade its priority.
|
||||
Thread t = FindThreadWithLowPriority();
|
||||
if(t != null)
|
||||
{
|
||||
UpgradeThreadPriority(t);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//If there are no tasks pending, find a thread with priority above Lowest and downgrade its priority.
|
||||
Thread t = FindThreadWithAcceptablePriority();
|
||||
if(t != null)
|
||||
{
|
||||
DowngradeThreadPriority(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//This part of code modifies the number of active threads based on the current performance of the threadpool
|
||||
if (statistics.PerformanceCounter >= 5)
|
||||
{
|
||||
if (threadpool.Count < this.maxThreads)
|
||||
{
|
||||
//Add a thread to the threadpool.
|
||||
//Reset counter to 0.
|
||||
statistics.PerformanceCounter = 0;
|
||||
WorkerThread worker = new WorkerThread();
|
||||
worker.thread = new Thread(() =>
|
||||
{
|
||||
ThreadMainLoop(ref worker);
|
||||
});
|
||||
worker.thread.Name = "ThreadPool WorkerThread";
|
||||
worker.running = true;
|
||||
worker.thread.Start();
|
||||
threadpool.Add(worker);
|
||||
}
|
||||
}
|
||||
else if(statistics.PerformanceCounter <= -10)
|
||||
{
|
||||
if (threadpool.Count > maxThreads / 4)
|
||||
{
|
||||
//Remove the last thread in the threadpool.
|
||||
//If thread is currently working, notify it to close.
|
||||
//Else, abort the thread.
|
||||
//Reset counter to 0.
|
||||
WorkerThread worker = threadpool[threadpool.Count - 1];
|
||||
if (worker.working)
|
||||
{
|
||||
worker.running = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
worker.thread.Abort();
|
||||
}
|
||||
threadpool.RemoveAt(threadpool.Count - 1);
|
||||
statistics.PerformanceCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Find a thread with Lowest or BelowNormal priority.
|
||||
/// </summary>
|
||||
/// <returns>Thread with low priority.</returns>
|
||||
private Thread FindThreadWithLowPriority()
|
||||
{
|
||||
foreach(WorkerThread t in threadpool)
|
||||
{
|
||||
if(t.thread.Priority == ThreadPriority.Lowest || t.thread.Priority == ThreadPriority.BelowNormal)
|
||||
{
|
||||
return t.thread;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Find a thread with BelowNormal or Normal priority.
|
||||
/// </summary>
|
||||
/// <returns>Thread with BelowNormal or Normal priority.</returns>
|
||||
private Thread FindThreadWithAcceptablePriority()
|
||||
{
|
||||
foreach (WorkerThread t in threadpool)
|
||||
{
|
||||
if (t.thread.Priority == ThreadPriority.Normal || t.thread.Priority == ThreadPriority.BelowNormal)
|
||||
{
|
||||
return t.thread;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Downgrades the priority of a thread one level.
|
||||
/// </summary>
|
||||
/// <param name="t">Thread to have its priority level downgraded.</param>
|
||||
/// <returns></returns>
|
||||
private void DowngradeThreadPriority(Thread t)
|
||||
{
|
||||
switch (t.Priority)
|
||||
{
|
||||
case ThreadPriority.Highest:
|
||||
t.Priority = ThreadPriority.AboveNormal;
|
||||
break;
|
||||
case ThreadPriority.AboveNormal:
|
||||
t.Priority = ThreadPriority.Normal;
|
||||
break;
|
||||
case ThreadPriority.Normal:
|
||||
t.Priority = ThreadPriority.BelowNormal;
|
||||
break;
|
||||
case ThreadPriority.BelowNormal:
|
||||
t.Priority = ThreadPriority.Lowest;
|
||||
break;
|
||||
case ThreadPriority.Lowest:
|
||||
t.Priority = ThreadPriority.Lowest;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Upgrades the priority of a thread one level.
|
||||
/// </summary>
|
||||
/// <param name="t">Thread to have its priority level upgraded.</param>
|
||||
/// <returns></returns>
|
||||
private void UpgradeThreadPriority(Thread t)
|
||||
{
|
||||
switch (t.Priority)
|
||||
{
|
||||
case ThreadPriority.Highest:
|
||||
t.Priority = ThreadPriority.Highest;
|
||||
break;
|
||||
case ThreadPriority.AboveNormal:
|
||||
t.Priority = ThreadPriority.Highest;
|
||||
break;
|
||||
case ThreadPriority.Normal:
|
||||
t.Priority = ThreadPriority.AboveNormal;
|
||||
break;
|
||||
case ThreadPriority.BelowNormal:
|
||||
t.Priority = ThreadPriority.Normal;
|
||||
break;
|
||||
case ThreadPriority.Lowest:
|
||||
t.Priority = ThreadPriority.BelowNormal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false;
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of the tasks as well as aborts all threads. Called by the public Dispose() method.
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach(WorkerThread worker in threadpool)
|
||||
if (observer != null)
|
||||
{
|
||||
observer.Abort();
|
||||
}
|
||||
foreach (WorkerThread worker in threadpool)
|
||||
{
|
||||
worker.thread.Abort();
|
||||
}
|
||||
threadpool.Clear();
|
||||
tasks.Clear();
|
||||
if (observer != null)
|
||||
{
|
||||
observer.Abort();
|
||||
}
|
||||
}
|
||||
threadpool = null;
|
||||
tasks = null;
|
||||
@@ -379,7 +587,9 @@ namespace SystemExtensions.Threading
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of the tasks as well as aborts all threads.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
@@ -35,17 +35,6 @@ namespace SystemExtensions.Collections.Tests
|
||||
{
|
||||
fibonacciHeap.Insert(i);
|
||||
}
|
||||
if (fibonacciHeap.RemoveMinimum() != 0)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
for (int i = 1; i < 1000; i++)
|
||||
{
|
||||
if (!fibonacciHeap.Contains(i))
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SystemExtensions.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SystemExtensions.Collections.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class TreapTests
|
||||
{
|
||||
private static int IntegerComparison(int x, int y)
|
||||
{
|
||||
if (x == y)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (x > y)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
Treap<int> treap = new Treap<int>(new Comparison<int>(IntegerComparison));
|
||||
[TestMethod()]
|
||||
public void TreapTest()
|
||||
{
|
||||
treap = new Treap<int>(new Comparison<int>(IntegerComparison));
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void InsertTest()
|
||||
{
|
||||
Random random = new Random();
|
||||
for(int i = 0; i < 1000; i++)
|
||||
{
|
||||
treap.Insert(random.Next(0, 5000));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void RemoveTest()
|
||||
{
|
||||
treap.Insert(60);
|
||||
treap.Insert(6);
|
||||
treap.Insert(5);
|
||||
treap.Remove(60);
|
||||
if(treap.Contains(60) || treap.Count > 2)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ClearTest()
|
||||
{
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
treap.Insert(random.Next(0, 5000));
|
||||
}
|
||||
treap.Clear();
|
||||
if(treap.Count > 0)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ContainsTest()
|
||||
{
|
||||
treap.Insert(50);
|
||||
treap.Insert(25);
|
||||
treap.Insert(991142);
|
||||
treap.Insert(12313);
|
||||
treap.Insert(24);
|
||||
treap.Insert(23);
|
||||
if (!treap.Contains(24))
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod()]
|
||||
public void ToArrayTest()
|
||||
{
|
||||
for(int i = 0; i < 1000; i++)
|
||||
{
|
||||
treap.Insert(i);
|
||||
}
|
||||
int[] arr = treap.ToArray();
|
||||
for(int i = 0; i < 1000; i++)
|
||||
{
|
||||
if(arr[i] != i)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@
|
||||
<Compile Include="Collections\BinaryHeapTests.cs" />
|
||||
<Compile Include="Collections\FibonacciHeapTests.cs" />
|
||||
<Compile Include="Collections\PriorityQueueTests.cs" />
|
||||
<Compile Include="Collections\TreapTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Threading\PriorityThreadPoolTests.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace SystemExtensions.Threading.Tests
|
||||
{
|
||||
threadPool.Dispose();
|
||||
threadPool = new PriorityThreadPool();
|
||||
if (threadPool.NumberOfThreads != System.Environment.ProcessorCount / 4)
|
||||
if (threadPool.NumberOfThreads != System.Environment.ProcessorCount)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
@@ -33,7 +33,7 @@ namespace SystemExtensions.Threading.Tests
|
||||
{
|
||||
threadPool.Dispose();
|
||||
threadPool = new PriorityThreadPool(4);
|
||||
if (threadPool.NumberOfThreads != 4 / 4)
|
||||
if (threadPool.NumberOfThreads != 4)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
@@ -102,7 +102,7 @@ namespace SystemExtensions.Threading.Tests
|
||||
{
|
||||
threadPool.Dispose();
|
||||
threadPool = new PriorityThreadPool(4);
|
||||
if (threadPool.NumberOfThreads != 4 / 4)
|
||||
if (threadPool.NumberOfThreads != 4)
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
@@ -116,13 +116,6 @@ namespace SystemExtensions.Threading.Tests
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("=====================================");
|
||||
System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads);
|
||||
System.Diagnostics.Debug.WriteLine("=====================================");
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
while (threadPool.NumberOfThreads != 1)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("=====================================");
|
||||
@@ -203,13 +196,6 @@ namespace SystemExtensions.Threading.Tests
|
||||
System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + taskPriority);
|
||||
}, null, taskPriority);
|
||||
}
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("=====================================");
|
||||
System.Diagnostics.Debug.WriteLine("Current threads in threadpool: " + threadPool.NumberOfThreads);
|
||||
System.Diagnostics.Debug.WriteLine("=====================================");
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
while (threadPool.NumberOfThreads != System.Environment.ProcessorCount / 4)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("=====================================");
|
||||
|
||||
Reference in New Issue
Block a user