From 95f2ab709fe7a1e9d7ea009d30a5cebf16fa7693 Mon Sep 17 00:00:00 2001 From: Alex Macocian Date: Mon, 22 Apr 2019 14:56:03 +0200 Subject: [PATCH] Implemented Treap and Treap tests. --- SystemExtensions/Collections/BinaryHeap.cs | 24 +- SystemExtensions/Collections/FibonacciHeap.cs | 17 +- SystemExtensions/Collections/PriorityQueue.cs | 34 +- SystemExtensions/Collections/Treap.cs | 243 +++++++++++++ SystemExtensions/Comparators.cs | 3 + SystemExtensions/Properties/AssemblyInfo.cs | 4 +- SystemExtensions/SystemExtensions.csproj | 9 +- .../Threading/PriorityThreadPool.cs | 340 ++++++++++++++---- .../Collections/FibonacciHeapTests.cs | 11 - .../Collections/TreapTests.cs | 106 ++++++ .../SystemExtensionsTests.csproj | 1 + .../Threading/PriorityThreadPoolTests.cs | 20 +- 12 files changed, 706 insertions(+), 106 deletions(-) create mode 100644 SystemExtensions/Collections/Treap.cs create mode 100644 SystemExtensionsTests/Collections/TreapTests.cs 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("=====================================");