diff --git a/kr3/MyPriorityQueue.Tests/MyPriorityQueue.Tests.csproj b/kr3/MyPriorityQueue.Tests/MyPriorityQueue.Tests.csproj new file mode 100644 index 0000000..40e283d --- /dev/null +++ b/kr3/MyPriorityQueue.Tests/MyPriorityQueue.Tests.csproj @@ -0,0 +1,21 @@ + + + + net6.0 + enable + + false + + + + + + + + + + + + + + diff --git a/kr3/MyPriorityQueue.Tests/Test.cs b/kr3/MyPriorityQueue.Tests/Test.cs new file mode 100644 index 0000000..3ba0586 --- /dev/null +++ b/kr3/MyPriorityQueue.Tests/Test.cs @@ -0,0 +1,112 @@ +namespace MyPriorityQueue.Tests; + +using MyPriorityQueue; +using NUnit.Framework; +using System.Collections.Generic; +using System.Threading; + +public class Tests +{ + [Test] + public void EnqueueSizeAndDequeueFromOneThread() + { + var priorityQueue = new PriorityQueue(); + priorityQueue.Enqueue(1231, -1); + priorityQueue.Enqueue(1231, 1); + Assert.AreEqual(2, priorityQueue.Size); + priorityQueue.Enqueue(1, 23); + Assert.AreEqual(3, priorityQueue.Size); + Assert.AreEqual(1, priorityQueue.Dequeue()); + Assert.AreEqual(2, priorityQueue.Size); + priorityQueue.Enqueue(12, 1); + Assert.AreEqual(3, priorityQueue.Size); + Assert.AreEqual(1231, priorityQueue.Dequeue()); + Assert.AreEqual(2, priorityQueue.Size); + Assert.AreEqual(12, priorityQueue.Dequeue()); + Assert.AreEqual(1, priorityQueue.Size); + Assert.AreEqual(1231, priorityQueue.Dequeue()); + Assert.AreEqual(0, priorityQueue.Size); + } + + [Test] + public void EnqueueFromDifferentThreads() + { + var priorityQueue = new PriorityQueue(); + var threads = new Thread[3]; + for (int i = 0; i < threads.Length; ++i) + { + var localI = i; + threads[i] = new Thread(() => + { + priorityQueue.Enqueue(localI, 1); + }); + } + foreach (var thread in threads) + { + thread.Start(); + } + foreach (var thread in threads) + { + thread.Join(); + } + Assert.AreEqual(3, priorityQueue.Size); + } + + [Test] + public void DequeueFromDifferentThreadsAndSavingFIFO() + { + var priorityQueue = new PriorityQueue(); + priorityQueue.Enqueue("true", 1); + priorityQueue.Enqueue("false", 1); + priorityQueue.Enqueue("abobus", 1); + var values = new string[3]; + var threads = new Thread[3]; + for (int i = 0; i < threads.Length; ++i) + { + var localI = i; + threads[i] = new Thread(() => + { + values[localI] = priorityQueue.Dequeue(); + }); + } + foreach (var thread in threads) + { + thread.Start(); + } + foreach (var thread in threads) + { + thread.Join(); + } + var correctValues = new string[3]; + correctValues[0] = "true"; + correctValues[1] = "false"; + correctValues[2] = "abobus"; + Assert.AreEqual(correctValues, values); + Assert.AreEqual(0, priorityQueue.Size); + } + + [Test] + public void EnqueueAndDequeueFromDifferentThreadsWithoutExceptions() + { + var priorityQueue = new PriorityQueue(); + + var threads = new Thread[2]; + threads[0] = new Thread(() => + { + priorityQueue.Dequeue(); + }); + threads[1] = new Thread(() => + { + priorityQueue.Enqueue("ololo", 131); + }); + foreach (var thread in threads) + { + thread.Start(); + } + foreach (var thread in threads) + { + thread.Join(); + } + Assert.AreEqual(0, priorityQueue.Size); + } +} diff --git a/kr3/MyPriorityQueue/IPriorityQueue.cs b/kr3/MyPriorityQueue/IPriorityQueue.cs new file mode 100644 index 0000000..ada326b --- /dev/null +++ b/kr3/MyPriorityQueue/IPriorityQueue.cs @@ -0,0 +1,26 @@ +namespace MyPriorityQueue; + +/// +/// Interface of thread-safe priority queue +/// +/// Type of value +public interface IPriorityQueue +{ + /// + /// Add value ant its priority to the priority queue + /// + /// Given value + /// Given priority + void Enqueue(TValue value, int priority); + + /// + /// Removes and returns the first founded value with the highest priority from the priority queue + /// + /// Value with the highest priority + TValue Dequeue(); + + /// + /// Returns the quantity of elements + /// + int Size { get; } +} diff --git a/kr3/MyPriorityQueue/MyPriorityQueue.csproj b/kr3/MyPriorityQueue/MyPriorityQueue.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/kr3/MyPriorityQueue/MyPriorityQueue.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/kr3/MyPriorityQueue/MyPriorityQueue.sln b/kr3/MyPriorityQueue/MyPriorityQueue.sln new file mode 100644 index 0000000..883d07f --- /dev/null +++ b/kr3/MyPriorityQueue/MyPriorityQueue.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32210.238 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyPriorityQueue", "MyPriorityQueue.csproj", "{B1F6ADA8-0C8E-4016-912A-B0193040CA8D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyPriorityQueue.Tests", "..\MyPriorityQueue.Tests\MyPriorityQueue.Tests.csproj", "{EA3D469B-6AD6-451A-9F64-D2479A4702A9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B1F6ADA8-0C8E-4016-912A-B0193040CA8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1F6ADA8-0C8E-4016-912A-B0193040CA8D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1F6ADA8-0C8E-4016-912A-B0193040CA8D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1F6ADA8-0C8E-4016-912A-B0193040CA8D}.Release|Any CPU.Build.0 = Release|Any CPU + {EA3D469B-6AD6-451A-9F64-D2479A4702A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA3D469B-6AD6-451A-9F64-D2479A4702A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA3D469B-6AD6-451A-9F64-D2479A4702A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA3D469B-6AD6-451A-9F64-D2479A4702A9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {42B04315-5D4D-4FA7-9A03-E4C34222BD0B} + EndGlobalSection +EndGlobal diff --git a/kr3/MyPriorityQueue/PriorityQueue.cs b/kr3/MyPriorityQueue/PriorityQueue.cs new file mode 100644 index 0000000..5e269eb --- /dev/null +++ b/kr3/MyPriorityQueue/PriorityQueue.cs @@ -0,0 +1,53 @@ +namespace MyPriorityQueue; + +using System.Collections.Generic; +using System.Linq; + +/// +/// Realisation of thread-safe priority queue interface +/// +/// Type of value +public class PriorityQueue : IPriorityQueue +{ + private readonly SortedList> elementsByPriority = new(); + private int counter = 0; + private readonly object locker = new(); + + public void Enqueue(TValue value, int priority) + { + lock (locker) + { + if (!elementsByPriority.ContainsKey(priority)) + { + elementsByPriority[priority] = new Queue(); + } + elementsByPriority[priority].Enqueue(value); + counter++; + Monitor.PulseAll(locker); + } + } + + public TValue Dequeue() + { + lock (locker) + { + while (counter == 0) + { + Monitor.Wait(locker); + } + + var maxPriority = elementsByPriority.Keys.Last(); + var element = elementsByPriority[maxPriority].Dequeue(); + + if (elementsByPriority[maxPriority].Count == 0) + { + elementsByPriority.Remove(maxPriority); + } + counter--; + + return element; + } + } + + public int Size => counter; +} diff --git a/kr3/MyPriorityQueue/Program.cs b/kr3/MyPriorityQueue/Program.cs new file mode 100644 index 0000000..30ec1d2 --- /dev/null +++ b/kr3/MyPriorityQueue/Program.cs @@ -0,0 +1,8 @@ +namespace MyPriorityQueue; + +public static class Program +{ + public static void Main(string[] args) + { + } +} \ No newline at end of file