diff --git a/SystemExtensions/Collections/BinaryHeap.cs b/SystemExtensions/Collections/BinaryHeap.cs
index 562f94f..7f181d0 100644
--- a/SystemExtensions/Collections/BinaryHeap.cs
+++ b/SystemExtensions/Collections/BinaryHeap.cs
@@ -7,8 +7,9 @@ using System.Threading.Tasks;
namespace SystemExtensions.Collections
{
///
- /// Binary heap implementation
+ /// Binary heap implementation.
///
+ /// Provided type.
public class BinaryHeap
{
#region Fields
@@ -17,6 +18,9 @@ namespace SystemExtensions.Collections
int capacity, count, initialCapacity;
#endregion
#region Properties
+ ///
+ /// Minimum value from the heap.
+ ///
public T Min
{
get
@@ -24,6 +28,9 @@ namespace SystemExtensions.Collections
return items[1];
}
}
+ ///
+ /// Maximum value from the heap.
+ ///
public T Max
{
get
@@ -31,6 +38,9 @@ namespace SystemExtensions.Collections
return items[count];
}
}
+ ///
+ /// Capacity of the heap.
+ ///
public int Capacity { get => capacity;
set
{
@@ -41,9 +51,16 @@ namespace SystemExtensions.Collections
}
}
}
+ ///
+ /// Number of elements in the heap.
+ ///
public int Count { get => count; }
#endregion
#region Constructors
+ ///
+ /// Constructor for a binary heap data structure.
+ ///
+ /// Function used to compare the elements.
public BinaryHeap(Comparison comparator)
{
capacity = 10;
@@ -51,6 +68,11 @@ namespace SystemExtensions.Collections
items = new T[capacity];
this.comparator = comparator;
}
+ ///
+ /// Constructor for a binary heap data structure.
+ ///
+ /// Function used to compare the elements.
+ /// Initial capacity of the heap. Used for initial alocation of the array.
public BinaryHeap(Comparison comparator, int capacity)
{
this.capacity = capacity;
diff --git a/SystemExtensions/Collections/FibonacciHeap.cs b/SystemExtensions/Collections/FibonacciHeap.cs
index d60633a..0cbfdfa 100644
--- a/SystemExtensions/Collections/FibonacciHeap.cs
+++ b/SystemExtensions/Collections/FibonacciHeap.cs
@@ -6,6 +6,10 @@ using System.Threading.Tasks;
namespace SystemExtensions.Collections
{
+ ///
+ /// Fibonacci Heap implementation. Implements IDisposable to clear the sub structure of the heap.
+ ///
+ /// Provided type
public class FibonacciHeap : IDisposable
{
#region Fields
@@ -36,6 +40,10 @@ namespace SystemExtensions.Collections
}
#endregion
#region Constructors
+ ///
+ /// Constructor for Fibonacci heap data structure.
+ ///
+ /// Function used to compare the elements.
public FibonacciHeap(Comparison comparator)
{
this.comparator = comparator;
@@ -100,7 +108,7 @@ namespace SystemExtensions.Collections
///
/// Determines whether the heap contains a specified value.
///
- /// Valye to locate in the heap.
+ /// Value to locate in the heap.
///
public bool Contains(T value)
{
@@ -418,6 +426,10 @@ namespace SystemExtensions.Collections
#endregion
#region IDisposable Support
private bool disposedValue = false;
+ ///
+ /// Disposes of the contents of the heap. Called by the public Dispose().
+ ///
+ ///
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
@@ -435,6 +447,9 @@ namespace SystemExtensions.Collections
disposedValue = true;
}
}
+ ///
+ /// Disposes of the contents of the heap.
+ ///
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
diff --git a/SystemExtensions/Collections/PriorityQueue.cs b/SystemExtensions/Collections/PriorityQueue.cs
index 88c698b..3f98f96 100644
--- a/SystemExtensions/Collections/PriorityQueue.cs
+++ b/SystemExtensions/Collections/PriorityQueue.cs
@@ -6,13 +6,20 @@ using System.Threading.Tasks;
namespace SystemExtensions.Collections
{
+ ///
+ /// 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.
+ ///
+ /// Provided type.
public class PriorityQueue
{
#region Fields
private BinaryHeap binaryHeap;
#endregion
-
#region Properties
+ ///
+ /// Returns the number of elements stored into the queue.
+ ///
public int Count
{
get
@@ -21,20 +28,29 @@ namespace SystemExtensions.Collections
}
}
#endregion
-
#region Constructors
+ ///
+ /// Constructor for priority queue data structure.
+ ///
+ /// Function used to compare the elements.
public PriorityQueue(Comparison comparator)
{
binaryHeap = new BinaryHeap(comparator);
}
#endregion
-
#region Public Methods
+ ///
+ /// Add provided value to the queue.
+ ///
+ /// Value to be added to the queue.
public void Enqueue(T value)
{
binaryHeap.Insert(value);
}
-
+ ///
+ /// Pops the queue and removes the highest priority value from the queue.
+ ///
+ /// Highest priority value from the queue
public T Dequeue()
{
if (Count > 0)
@@ -46,18 +62,22 @@ namespace SystemExtensions.Collections
throw new IndexOutOfRangeException("Queue is empty!");
}
}
-
+ ///
+ /// Looks up the highest priority value from the queue. Doesn't alter the queue in any way.
+ ///
+ /// Highest priority value from the queue.
public T Peek()
{
return binaryHeap.Min;
}
-
+ ///
+ /// Clears the queue contents, removing any value stored into the queue.
+ ///
public void Clear()
{
binaryHeap.Clear();
}
#endregion
-
#region Private Methods
#endregion
}
diff --git a/SystemExtensions/Collections/Treap.cs b/SystemExtensions/Collections/Treap.cs
new file mode 100644
index 0000000..1ea78fc
--- /dev/null
+++ b/SystemExtensions/Collections/Treap.cs
@@ -0,0 +1,243 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SystemExtensions.Collections
+{
+ ///
+ /// Treap implementation.
+ ///
+ /// Provided type.
+ public class Treap
+ {
+ #region Fields
+ private Random randomGen;
+ private Item root;
+ private Comparison comparator;
+ private int count;
+ #endregion
+ #region Properties
+ ///
+ /// Count of values in the treap.
+ ///
+ public int Count
+ {
+ get
+ {
+ return count;
+ }
+ }
+ #endregion
+ #region Constructors
+ ///
+ /// Constructor for treap.
+ ///
+ /// Comparator method used to compare values.
+ public Treap(Comparison comparator)
+ {
+ randomGen = new Random();
+ this.comparator = comparator;
+ }
+ #endregion
+ #region Private Methods
+ private Item InsertNode(Item node, T key)
+ {
+ if(node == null) {
+ node = new Item(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 RemoveNode(Item 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 RotateRight(Item node)
+ {
+ Item temp = node.Left, temp2 = temp.Right;
+ temp.Right = node;
+ node.Left = temp2;
+ return temp;
+ }
+ private Item RotateLeft(Item node)
+ {
+ Item temp = node.Right, temp2 = temp.Left;
+ temp.Left = node;
+ node.Right = temp2;
+ return temp;
+ }
+ private void Clear(Item node)
+ {
+ if(node.Left != null)
+ {
+ Clear(node.Left);
+ }
+ if(node.Right != null)
+ {
+ Clear(node.Right);
+ }
+ node.Left = node.Right = null;
+ }
+ private Item Find(Item node, T key)
+ {
+ if(node == null)
+ {
+ return node;
+ }
+ else
+ {
+ if(comparator.Invoke(node.Key, key) < 0)
+ {
+ Item found = Find(node.Left, key);
+ if(found == null)
+ {
+ found = Find(node.Right, key);
+ }
+ return found;
+ }
+ else if(comparator.Invoke(node.Key, key) > 0)
+ {
+ Item found = Find(node.Right, key);
+ if (found == null)
+ {
+ found = Find(node.Left, key);
+ }
+ return found;
+ }
+ else
+ {
+ return node;
+ }
+ }
+ }
+ private void ToArray(Item 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
+ ///
+ /// Inserts value into treap.
+ ///
+ /// Value to be inserted.
+ public void Insert(T value)
+ {
+ root = InsertNode(root, value);
+ count++;
+ }
+ ///
+ /// Removes value from treap.
+ ///
+ /// Value to be removed.
+ public void Remove(T value)
+ {
+ root = RemoveNode(root, value);
+ count--;
+ }
+ ///
+ /// Clears the treap.
+ ///
+ public void Clear()
+ {
+ Clear(root);
+ root = null;
+ count = 0;
+ }
+ ///
+ /// Determines whether the treap contains the specified value.
+ ///
+ /// Value to locate in the treap.
+ ///
+ public bool Contains(T value)
+ {
+ return Find(root, value) != null;
+ }
+ ///
+ /// Returns the treap structure as an ordered array.
+ ///
+ /// Ordered array containing the values stored in the treap.
+ 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
+ {
+ public T Key;
+ public int Priority;
+ public Item Left, Right;
+ public Item(T key, int priority)
+ {
+ Key = key;
+ Priority = priority;
+ Left = null;
+ Right = null;
+ }
+ }
+}
diff --git a/SystemExtensions/Comparators.cs b/SystemExtensions/Comparators.cs
index a309a5b..e04c877 100644
--- a/SystemExtensions/Comparators.cs
+++ b/SystemExtensions/Comparators.cs
@@ -6,6 +6,9 @@ using System.Threading.Tasks;
namespace SystemExtensions
{
+ ///
+ /// Static class containing implementation of comparators to be used when creating and using collections.
+ ///
public static class Comparators
{
#region Fields
diff --git a/SystemExtensions/Properties/AssemblyInfo.cs b/SystemExtensions/Properties/AssemblyInfo.cs
index 992da5f..327d7c0 100644
--- a/SystemExtensions/Properties/AssemblyInfo.cs
+++ b/SystemExtensions/Properties/AssemblyInfo.cs
@@ -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("")]
diff --git a/SystemExtensions/SystemExtensions.csproj b/SystemExtensions/SystemExtensions.csproj
index 79f3be0..409f245 100644
--- a/SystemExtensions/SystemExtensions.csproj
+++ b/SystemExtensions/SystemExtensions.csproj
@@ -7,11 +7,12 @@
{55850FF3-70E4-4828-BEEE-39837AC0D24C}
Library
Properties
- PriorityThreadPool
- PriorityThreadPool
+ SystemExtensions
+ SystemExtensions
v4.6.1
512
true
+
true
@@ -21,6 +22,8 @@
DEBUG;TRACE
prompt
4
+ bin\Debug\SystemExtensions.xml
+ false
pdbonly
@@ -29,6 +32,7 @@
TRACE
prompt
4
+ false
@@ -44,6 +48,7 @@
+
diff --git a/SystemExtensions/Threading/PriorityThreadPool.cs b/SystemExtensions/Threading/PriorityThreadPool.cs
index a624309..c62cbaf 100644
--- a/SystemExtensions/Threading/PriorityThreadPool.cs
+++ b/SystemExtensions/Threading/PriorityThreadPool.cs
@@ -8,6 +8,11 @@ using SystemExtensions.Collections;
namespace SystemExtensions.Threading
{
+ ///
+ /// 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.
+ ///
public class PriorityThreadPool : IDisposable
{
#region Enum
@@ -16,10 +21,25 @@ namespace SystemExtensions.Threading
///
public enum TaskPriority
{
+ ///
+ /// Highest priority of a task.
+ ///
Highest,
+ ///
+ /// Priority level above the default level.
+ ///
AboveNormal,
+ ///
+ /// Default priority level of all tasks without a specified priority level.
+ ///
Normal,
+ ///
+ /// Priority level below the default level.
+ ///
BelowNormal,
+ ///
+ /// Lowest priority level.
+ ///
Lowest
}
#endregion
@@ -27,8 +47,8 @@ namespace SystemExtensions.Threading
///
/// List that contains current running threads and their status.
///
- private List threadpool;
- private PriorityQueue> tasks;
+ private volatile List threadpool;
+ private volatile PriorityQueue> 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
+ ///
+ /// Returns the number of active threads in the threadpool.
+ ///
public int NumberOfThreads
{
get
@@ -47,8 +76,31 @@ namespace SystemExtensions.Threading
return threadpool.Count;
}
}
+ ///
+ /// Returns true if there are no tasks queued.
+ ///
+ public bool Empty
+ {
+ get
+ {
+ return tasks.Count == 0;
+ }
+ }
+ ///
+ /// Maximum amount of threads that the pool can utilize
+ ///
+ public int MaxThreads
+ {
+ set
+ {
+ maxThreads = value;
+ }
+ get
+ {
+ return maxThreads;
+ }
+ }
#endregion
-
#region Constructors
///
/// 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();
tasks = new PriorityQueue>(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();
}
///
@@ -87,15 +140,15 @@ namespace SystemExtensions.Threading
threadpool = new List();
tasks = new PriorityQueue>(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();
}
///
@@ -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
+ ///
+ /// Add a work item into the queue.
+ ///
+ /// WaitCallBack delegate that will be invoked by the threads.
+ /// State used as parameter during invoke.
+ /// Priority of task. Affects its position into the queue.
public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState, TaskPriority taskPriority)
{
while (!Monitor.TryEnter(tasksLock));
tasks.Enqueue(new Tuple(taskPriority, waitCallback, callbackState));
Monitor.Exit(tasksLock);
}
-
+ ///
+ /// Add a work item into the queue.
+ ///
+ /// WaitCallBack delegate that will be invoked by the threads.
+ /// State used as parameter during invoke.
public void QueueUserWorkItem(WaitCallback waitCallback, object callbackState)
{
QueueUserWorkItem(waitCallback, callbackState, TaskPriority.Normal);
}
#endregion
-
#region Private Methods
///
/// 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.
///
/// Id of thread
- 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
///
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;
+ }
+ }
+ }
+ }
+ ///
+ /// Find a thread with Lowest or BelowNormal priority.
+ ///
+ /// Thread with low priority.
+ private Thread FindThreadWithLowPriority()
+ {
+ foreach(WorkerThread t in threadpool)
+ {
+ if(t.thread.Priority == ThreadPriority.Lowest || t.thread.Priority == ThreadPriority.BelowNormal)
+ {
+ return t.thread;
+ }
+ }
+ return null;
+ }
+ ///
+ /// Find a thread with BelowNormal or Normal priority.
+ ///
+ /// Thread with BelowNormal or Normal priority.
+ private Thread FindThreadWithAcceptablePriority()
+ {
+ foreach (WorkerThread t in threadpool)
+ {
+ if (t.thread.Priority == ThreadPriority.Normal || t.thread.Priority == ThreadPriority.BelowNormal)
+ {
+ return t.thread;
+ }
+ }
+ return null;
+ }
+ ///
+ /// Downgrades the priority of a thread one level.
+ ///
+ /// Thread to have its priority level downgraded.
+ ///
+ 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;
+ }
+ }
+ ///
+ /// Upgrades the priority of a thread one level.
+ ///
+ /// Thread to have its priority level upgraded.
+ ///
+ 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;
-
+ ///
+ /// Disposes of the tasks as well as aborts all threads. Called by the public Dispose() method.
+ ///
+ ///
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;
}
}
-
+ ///
+ /// Disposes of the tasks as well as aborts all threads.
+ ///
public void Dispose()
{
Dispose(true);
diff --git a/SystemExtensionsTests/Collections/FibonacciHeapTests.cs b/SystemExtensionsTests/Collections/FibonacciHeapTests.cs
index 814579a..ba8635f 100644
--- a/SystemExtensionsTests/Collections/FibonacciHeapTests.cs
+++ b/SystemExtensionsTests/Collections/FibonacciHeapTests.cs
@@ -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()]
diff --git a/SystemExtensionsTests/Collections/TreapTests.cs b/SystemExtensionsTests/Collections/TreapTests.cs
new file mode 100644
index 0000000..7af765f
--- /dev/null
+++ b/SystemExtensionsTests/Collections/TreapTests.cs
@@ -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 treap = new Treap(new Comparison(IntegerComparison));
+ [TestMethod()]
+ public void TreapTest()
+ {
+ treap = new Treap(new Comparison(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();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/SystemExtensionsTests/SystemExtensionsTests.csproj b/SystemExtensionsTests/SystemExtensionsTests.csproj
index 8165f6e..04b2858 100644
--- a/SystemExtensionsTests/SystemExtensionsTests.csproj
+++ b/SystemExtensionsTests/SystemExtensionsTests.csproj
@@ -59,6 +59,7 @@
+
diff --git a/SystemExtensionsTests/Threading/PriorityThreadPoolTests.cs b/SystemExtensionsTests/Threading/PriorityThreadPoolTests.cs
index 8091ccc..9124d6f 100644
--- a/SystemExtensionsTests/Threading/PriorityThreadPoolTests.cs
+++ b/SystemExtensionsTests/Threading/PriorityThreadPoolTests.cs
@@ -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("=====================================");