Implemented Treap and Treap tests.

This commit is contained in:
Alex Macocian
2019-04-22 14:56:03 +02:00
parent afdfeda826
commit 95f2ab709f
12 changed files with 706 additions and 106 deletions
+23 -1
View File
@@ -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;
+16 -1
View File
@@ -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.
+27 -7
View File
@@ -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
}
+243
View File
@@ -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;
}
}
}
+3
View File
@@ -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
+2 -2
View File
@@ -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 -2
View File
@@ -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" />
+275 -65
View File
@@ -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("=====================================");