From 819d66b81888096fa68da72e4e3736ea21d0ba32 Mon Sep 17 00:00:00 2001 From: Artem Date: Fri, 29 Sep 2023 21:43:52 +0300 Subject: [PATCH 01/17] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool.sln | 25 +++++++++++++++++++ MyThreadPool/MyThreadPool/IMyTask.cs | 8 ++++++ MyThreadPool/MyThreadPool/MyThread.cs | 24 ++++++++++++++++++ MyThreadPool/MyThreadPool/MyThreadPool.cs | 19 ++++++++++++++ MyThreadPool/MyThreadPool/MyThreadPool.csproj | 10 ++++++++ 5 files changed, 86 insertions(+) create mode 100644 MyThreadPool/MyThreadPool.sln create mode 100644 MyThreadPool/MyThreadPool/IMyTask.cs create mode 100644 MyThreadPool/MyThreadPool/MyThread.cs create mode 100644 MyThreadPool/MyThreadPool/MyThreadPool.cs create mode 100644 MyThreadPool/MyThreadPool/MyThreadPool.csproj diff --git a/MyThreadPool/MyThreadPool.sln b/MyThreadPool/MyThreadPool.sln new file mode 100644 index 0000000..a924826 --- /dev/null +++ b/MyThreadPool/MyThreadPool.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33403.182 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyThreadPool", "MyThreadPool\MyThreadPool.csproj", "{571D564D-1D0C-469E-857E-D0D1390DC178}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {571D564D-1D0C-469E-857E-D0D1390DC178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {571D564D-1D0C-469E-857E-D0D1390DC178}.Debug|Any CPU.Build.0 = Debug|Any CPU + {571D564D-1D0C-469E-857E-D0D1390DC178}.Release|Any CPU.ActiveCfg = Release|Any CPU + {571D564D-1D0C-469E-857E-D0D1390DC178}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B78A1404-BCEF-4F4C-93D1-CCA4EFF20DB0} + EndGlobalSection +EndGlobal diff --git a/MyThreadPool/MyThreadPool/IMyTask.cs b/MyThreadPool/MyThreadPool/IMyTask.cs new file mode 100644 index 0000000..fb6bc85 --- /dev/null +++ b/MyThreadPool/MyThreadPool/IMyTask.cs @@ -0,0 +1,8 @@ +namespace MyThreadPool; + +public interface IMyTask +{ + public bool IsCompleted { get; } + public TResult Result { get; } + +} \ No newline at end of file diff --git a/MyThreadPool/MyThreadPool/MyThread.cs b/MyThreadPool/MyThreadPool/MyThread.cs new file mode 100644 index 0000000..9ef19b2 --- /dev/null +++ b/MyThreadPool/MyThreadPool/MyThread.cs @@ -0,0 +1,24 @@ +namespace MyThreadPool; + +public class MyThread +{ + private volatile bool isActive = false; + private Thread thread; + public MyThread() {} + + public TResult AdddFunction(Func resultFunction) + { + object value = null; + while (isActive) + { + + } + thread = new Thread(() => { value = resultFunction(); }); + return (TResult)value; + } + + public bool isActiveThread() + { + return isActive; + } +} diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs new file mode 100644 index 0000000..40464c4 --- /dev/null +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -0,0 +1,19 @@ +namespace MyThreadPool; + +public class MyThreadPool +{ + private static MyThread[] arrayThread; + public MyThreadPool(int sizeThreads) + { + arrayThread = new MyThread[sizeThreads]; + for (int i = 0; i < sizeThreads; i++) + { + + } + } + + public void Shutdown() + { + + } +} \ No newline at end of file diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.csproj b/MyThreadPool/MyThreadPool/MyThreadPool.csproj new file mode 100644 index 0000000..f02677b --- /dev/null +++ b/MyThreadPool/MyThreadPool/MyThreadPool.csproj @@ -0,0 +1,10 @@ + + + + Exe + net7.0 + enable + enable + + + From 76f2240f09bd5aba338dda758da16e2307f7f77d Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 2 Oct 2023 21:40:06 +0300 Subject: [PATCH 02/17] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20IMyTask=20=D0=B8=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=B4?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/IMyTask.cs | 2 +- MyThreadPool/MyThreadPool/MyTask.cs | 43 ++++++++++++++++++ MyThreadPool/MyThreadPool/MyThread.cs | 55 ++++++++++++++++++----- MyThreadPool/MyThreadPool/MyThreadPool.cs | 36 ++++++++++++++- 4 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 MyThreadPool/MyThreadPool/MyTask.cs diff --git a/MyThreadPool/MyThreadPool/IMyTask.cs b/MyThreadPool/MyThreadPool/IMyTask.cs index fb6bc85..6cf864f 100644 --- a/MyThreadPool/MyThreadPool/IMyTask.cs +++ b/MyThreadPool/MyThreadPool/IMyTask.cs @@ -4,5 +4,5 @@ public interface IMyTask { public bool IsCompleted { get; } public TResult Result { get; } - + //public ContinueWith } \ No newline at end of file diff --git a/MyThreadPool/MyThreadPool/MyTask.cs b/MyThreadPool/MyThreadPool/MyTask.cs new file mode 100644 index 0000000..d5c5706 --- /dev/null +++ b/MyThreadPool/MyThreadPool/MyTask.cs @@ -0,0 +1,43 @@ +namespace MyThreadPool; + +public class MyTask : IMyTask +{ + private Func? suppiler; + private volatile bool isCompleted = false; + private TResult? result; + + public MyTask(Func suppiler) + { + this.suppiler = suppiler; + } + + public TResult Result + { + get + { + while (!isCompleted) {} + return result; + } + } + public bool IsCompleted + { + get + { + return isCompleted; + } + } + + public Func GetSupplier() + { + return suppiler; + } + + public void StartSuppiler() + { + if (suppiler != null) + { + result = suppiler(); + isCompleted = true; + } + } +} \ No newline at end of file diff --git a/MyThreadPool/MyThreadPool/MyThread.cs b/MyThreadPool/MyThreadPool/MyThread.cs index 9ef19b2..4989453 100644 --- a/MyThreadPool/MyThreadPool/MyThread.cs +++ b/MyThreadPool/MyThreadPool/MyThread.cs @@ -1,24 +1,59 @@ -namespace MyThreadPool; +using System.Reflection.Metadata.Ecma335; + +namespace MyThreadPool; public class MyThread { private volatile bool isActive = false; - private Thread thread; - public MyThread() {} + private volatile bool isAlive = true; + private Thread? thread; + private MyTask? task; - public TResult AdddFunction(Func resultFunction) + public MyThread() { - object value = null; - while (isActive) + thread = new Thread(() => EternalCycle()); + thread.Start(); + } + + public bool IsActive() + { + return isActive; + } + + private void EternalCycle() + { + while (isAlive) { + while (task == null || task.IsCompleted) { } + isActive = true; + try + { + task.StartSuppiler(); + } + catch (Exception ex) + { + throw new AggregateException(ex); + } + isActive = false; } - thread = new Thread(() => { value = resultFunction(); }); - return (TResult)value; } - public bool isActiveThread() + public void KillThread() { - return isActive; + isAlive = false; + } + + public bool IsAlive() + { + return isAlive; + } + + public void GiveTask(MyTask task) + { + if (isAlive) + { + this.task = task; + } } } diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index 40464c4..b614c0c 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -1,4 +1,6 @@ -namespace MyThreadPool; +using System.IO; + +namespace MyThreadPool; public class MyThreadPool { @@ -8,12 +10,42 @@ public MyThreadPool(int sizeThreads) arrayThread = new MyThread[sizeThreads]; for (int i = 0; i < sizeThreads; i++) { + arrayThread[i] = new MyThread(); + } + } + public TResult GetTask(Func suppiler) + { + TResult? result; + while (true) + { + for (int i = 0; i < arrayThread.Length; i++) + { + if (!arrayThread[i].IsActive()) + { + var newTask = new MyTask(suppiler); + arrayThread[i].GiveTask(newTask); + result = newTask.Result; + newTask = null; + return result; + } + } } } public void Shutdown() { - + int disabledThreads = 0; + while (disabledThreads < arrayThread.Length) + { + for (int i = 0; i < arrayThread.Length; ++i) + { + if (arrayThread[i].IsAlive() && !arrayThread[i].IsActive()) + { + arrayThread[i].KillThread(); + ++disabledThreads; + } + } + } } } \ No newline at end of file From 4449498dfdfa5308b054b2516750fdb319825538 Mon Sep 17 00:00:00 2001 From: Artem Date: Fri, 6 Oct 2023 17:34:08 +0300 Subject: [PATCH 03/17] =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/IMyTask.cs | 2 +- MyThreadPool/MyThreadPool/MyTask.cs | 35 ++++++++++++++++- MyThreadPool/MyThreadPool/MyThread.cs | 46 +++++++++++------------ MyThreadPool/MyThreadPool/MyThreadPool.cs | 41 +++++++------------- 4 files changed, 72 insertions(+), 52 deletions(-) diff --git a/MyThreadPool/MyThreadPool/IMyTask.cs b/MyThreadPool/MyThreadPool/IMyTask.cs index 6cf864f..fdec2f4 100644 --- a/MyThreadPool/MyThreadPool/IMyTask.cs +++ b/MyThreadPool/MyThreadPool/IMyTask.cs @@ -4,5 +4,5 @@ public interface IMyTask { public bool IsCompleted { get; } public TResult Result { get; } - //public ContinueWith + public IMyTask ContinueWith(Func suppiler); } \ No newline at end of file diff --git a/MyThreadPool/MyThreadPool/MyTask.cs b/MyThreadPool/MyThreadPool/MyTask.cs index d5c5706..a4890f9 100644 --- a/MyThreadPool/MyThreadPool/MyTask.cs +++ b/MyThreadPool/MyThreadPool/MyTask.cs @@ -5,10 +5,17 @@ public class MyTask : IMyTask private Func? suppiler; private volatile bool isCompleted = false; private TResult? result; + private Queue queueWithContinueWithTasks; + private MyThread[] arrayThreads; + private Queue queueWithTasks; + private Object locker = new Object(); - public MyTask(Func suppiler) + public MyTask(Func suppiler, MyThread[] arrayThreads, Queue queueWithTasks) { this.suppiler = suppiler; + queueWithContinueWithTasks = new (); + this.arrayThreads = arrayThreads; + this.queueWithTasks = queueWithTasks; } public TResult Result @@ -38,6 +45,32 @@ public void StartSuppiler() { result = suppiler(); isCompleted = true; + while (queueWithContinueWithTasks.Count > 0) + { + queueWithTasks.Enqueue(queueWithContinueWithTasks.Dequeue()); + } } } + + public bool IsQueueEmpty() + { + return queueWithContinueWithTasks.Count == 0; + } + + public IMyTask ContinueWith(Func suppiler) + { + var newTask = new MyTask(() => suppiler(Result), arrayThreads, queueWithTasks); + lock(locker) + { + if (IsCompleted) + { + queueWithTasks.Enqueue(() => newTask.StartSuppiler()); + } + else + { + queueWithContinueWithTasks.Enqueue(() => newTask.StartSuppiler()); + } + } + return newTask; + } } \ No newline at end of file diff --git a/MyThreadPool/MyThreadPool/MyThread.cs b/MyThreadPool/MyThreadPool/MyThread.cs index 4989453..b8adec8 100644 --- a/MyThreadPool/MyThreadPool/MyThread.cs +++ b/MyThreadPool/MyThreadPool/MyThread.cs @@ -1,18 +1,18 @@ -using System.Reflection.Metadata.Ecma335; +namespace MyThreadPool; -namespace MyThreadPool; - -public class MyThread +public class MyThread { private volatile bool isActive = false; private volatile bool isAlive = true; private Thread? thread; - private MyTask? task; + private volatile Queue tasks; + private Object locker = new Object(); - public MyThread() + public MyThread(Queue tasks) { thread = new Thread(() => EternalCycle()); thread.Start(); + this.tasks = tasks; } public bool IsActive() @@ -22,20 +22,28 @@ public bool IsActive() private void EternalCycle() { + Action? task = null; while (isAlive) { - while (task == null || task.IsCompleted) { } - isActive = true; - try - { - task.StartSuppiler(); - } - catch (Exception ex) + while (tasks.Count == 0) { } + lock (locker) { - throw new AggregateException(ex); + task = tasks.Dequeue(); } + if (task != null) + { - isActive = false; + isActive = true; + try + { + task(); + } + catch (Exception ex) + { + throw new AggregateException(ex); + } + isActive = false; + } } } @@ -48,12 +56,4 @@ public bool IsAlive() { return isAlive; } - - public void GiveTask(MyTask task) - { - if (isAlive) - { - this.task = task; - } - } } diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index b614c0c..615e6aa 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -1,48 +1,35 @@ -using System.IO; +namespace MyThreadPool; -namespace MyThreadPool; - -public class MyThreadPool +public class MyThreadPool { - private static MyThread[] arrayThread; + private static MyThread[]? arrayThreads; + private static Queue tasks = new (); public MyThreadPool(int sizeThreads) { - arrayThread = new MyThread[sizeThreads]; + arrayThreads = new MyThread[sizeThreads]; for (int i = 0; i < sizeThreads; i++) { - arrayThread[i] = new MyThread(); + arrayThreads[i] = new MyThread(tasks); } } - public TResult GetTask(Func suppiler) + public IMyTask Submit(Func suppiler) { - TResult? result; - while (true) - { - for (int i = 0; i < arrayThread.Length; i++) - { - if (!arrayThread[i].IsActive()) - { - var newTask = new MyTask(suppiler); - arrayThread[i].GiveTask(newTask); - result = newTask.Result; - newTask = null; - return result; - } - } - } + var newTask = new MyTask(suppiler, arrayThreads, tasks); + tasks.Enqueue(() => newTask.StartSuppiler()); + return newTask; } public void Shutdown() { int disabledThreads = 0; - while (disabledThreads < arrayThread.Length) + while (disabledThreads < arrayThreads.Length) { - for (int i = 0; i < arrayThread.Length; ++i) + for (int i = 0; i < arrayThreads.Length; ++i) { - if (arrayThread[i].IsAlive() && !arrayThread[i].IsActive()) + if (arrayThreads[i].IsAlive() && !arrayThreads[i].IsActive()) { - arrayThread[i].KillThread(); + arrayThreads[i].KillThread(); ++disabledThreads; } } From 0351153a7cd93939232843f07bd98cc43aebb707 Mon Sep 17 00:00:00 2001 From: Artem Date: Fri, 6 Oct 2023 20:13:51 +0300 Subject: [PATCH 04/17] =?UTF-8?q?=D0=A2=D0=B5=D1=81=D1=82=D1=8B=20=D0=B8?= =?UTF-8?q?=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool.sln | 8 +- MyThreadPool/MyThreadPool/IMyTask.cs | 8 +- MyThreadPool/MyThreadPool/MyTask.cs | 19 +++-- MyThreadPool/MyThreadPool/MyThread.cs | 27 ++++++- MyThreadPool/MyThreadPool/MyThreadPool.cs | 26 ++++++- .../TestsForMyThreadPool.cs | 76 +++++++++++++++++++ .../TestsForMyThreadPool.csproj | 23 ++++++ MyThreadPool/TestsForMyThreadPool/Usings.cs | 1 + 8 files changed, 176 insertions(+), 12 deletions(-) create mode 100644 MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs create mode 100644 MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.csproj create mode 100644 MyThreadPool/TestsForMyThreadPool/Usings.cs diff --git a/MyThreadPool/MyThreadPool.sln b/MyThreadPool/MyThreadPool.sln index a924826..f05a317 100644 --- a/MyThreadPool/MyThreadPool.sln +++ b/MyThreadPool/MyThreadPool.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.4.33403.182 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyThreadPool", "MyThreadPool\MyThreadPool.csproj", "{571D564D-1D0C-469E-857E-D0D1390DC178}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyThreadPool", "MyThreadPool\MyThreadPool.csproj", "{571D564D-1D0C-469E-857E-D0D1390DC178}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsForMyThreadPool", "TestsForMyThreadPool\TestsForMyThreadPool.csproj", "{EDDD394B-53B2-4A35-916C-7AEB2FBF3728}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {571D564D-1D0C-469E-857E-D0D1390DC178}.Debug|Any CPU.Build.0 = Debug|Any CPU {571D564D-1D0C-469E-857E-D0D1390DC178}.Release|Any CPU.ActiveCfg = Release|Any CPU {571D564D-1D0C-469E-857E-D0D1390DC178}.Release|Any CPU.Build.0 = Release|Any CPU + {EDDD394B-53B2-4A35-916C-7AEB2FBF3728}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDDD394B-53B2-4A35-916C-7AEB2FBF3728}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDDD394B-53B2-4A35-916C-7AEB2FBF3728}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDDD394B-53B2-4A35-916C-7AEB2FBF3728}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MyThreadPool/MyThreadPool/IMyTask.cs b/MyThreadPool/MyThreadPool/IMyTask.cs index fdec2f4..18e1e74 100644 --- a/MyThreadPool/MyThreadPool/IMyTask.cs +++ b/MyThreadPool/MyThreadPool/IMyTask.cs @@ -1,8 +1,14 @@ namespace MyThreadPool; +/// +/// Interface for creating tasks +/// public interface IMyTask { public bool IsCompleted { get; } - public TResult Result { get; } + public TResult? Result { get; } + /// + /// A method for solving subtasks from the results obtained from the tasks + /// public IMyTask ContinueWith(Func suppiler); } \ No newline at end of file diff --git a/MyThreadPool/MyThreadPool/MyTask.cs b/MyThreadPool/MyThreadPool/MyTask.cs index a4890f9..0f2885a 100644 --- a/MyThreadPool/MyThreadPool/MyTask.cs +++ b/MyThreadPool/MyThreadPool/MyTask.cs @@ -1,5 +1,8 @@ namespace MyThreadPool; +/// +/// A class for creating tasks +/// public class MyTask : IMyTask { private Func? suppiler; @@ -10,6 +13,9 @@ public class MyTask : IMyTask private Queue queueWithTasks; private Object locker = new Object(); + /// + /// Constructor for creating a task + /// public MyTask(Func suppiler, MyThread[] arrayThreads, Queue queueWithTasks) { this.suppiler = suppiler; @@ -18,7 +24,7 @@ public MyTask(Func suppiler, MyThread[] arrayThreads, Queue que this.queueWithTasks = queueWithTasks; } - public TResult Result + public TResult? Result { get { @@ -34,11 +40,9 @@ public bool IsCompleted } } - public Func GetSupplier() - { - return suppiler; - } - + /// + /// Task completion + /// public void StartSuppiler() { if (suppiler != null) @@ -52,6 +56,9 @@ public void StartSuppiler() } } + /// + /// Checking that the task queue is empty + /// public bool IsQueueEmpty() { return queueWithContinueWithTasks.Count == 0; diff --git a/MyThreadPool/MyThreadPool/MyThread.cs b/MyThreadPool/MyThreadPool/MyThread.cs index b8adec8..c52803b 100644 --- a/MyThreadPool/MyThreadPool/MyThread.cs +++ b/MyThreadPool/MyThreadPool/MyThread.cs @@ -1,5 +1,8 @@ namespace MyThreadPool; +/// +/// A class of native threads responsible for executing tasks +/// public class MyThread { private volatile bool isActive = false; @@ -7,32 +10,46 @@ public class MyThread private Thread? thread; private volatile Queue tasks; private Object locker = new Object(); + private CancellationToken token; - public MyThread(Queue tasks) + /// + /// Task-based custom thread constructor + /// + public MyThread(Queue tasks, CancellationToken token) { thread = new Thread(() => EternalCycle()); thread.Start(); this.tasks = tasks; + this.token = token; } + /// + /// Checks if the thread is busy + /// public bool IsActive() { return isActive; } + /// + /// Task waiting cycle + /// private void EternalCycle() { Action? task = null; while (isAlive) { while (tasks.Count == 0) { } + if (token.IsCancellationRequested) + { + break; + } lock (locker) { task = tasks.Dequeue(); } if (task != null) { - isActive = true; try { @@ -47,11 +64,17 @@ private void EternalCycle() } } + /// + /// Eliminating threads + /// public void KillThread() { isAlive = false; } + /// + /// Checking whether the thread is alive + /// public bool IsAlive() { return isAlive; diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index 615e6aa..3c2c16e 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -1,18 +1,33 @@ namespace MyThreadPool; +/// +/// A class for automatic efficient flow control in the program. +/// public class MyThreadPool { private static MyThread[]? arrayThreads; private static Queue tasks = new (); + private CancellationToken token = new CancellationToken(); + + /// + /// Constructor for creating n number of threads for tasks + /// public MyThreadPool(int sizeThreads) { + if (sizeThreads <= 0) + { + throw new ArgumentOutOfRangeException(); + } arrayThreads = new MyThread[sizeThreads]; for (int i = 0; i < sizeThreads; i++) { - arrayThreads[i] = new MyThread(tasks); + arrayThreads[i] = new MyThread(tasks, token); } } + /// + /// Accepts a function, adds it as a task in the thread, and returns the created task + /// public IMyTask Submit(Func suppiler) { var newTask = new MyTask(suppiler, arrayThreads, tasks); @@ -20,8 +35,15 @@ public IMyTask Submit(Func suppiler) return newTask; } - public void Shutdown() + /// + /// Interrupts the processing of tasks that are not started do not begin, and those that are started are being completed + /// + public void Shutdown(CancellationToken tokenFromUser) { + if (tokenFromUser.IsCancellationRequested) + { + token.ThrowIfCancellationRequested(); + } int disabledThreads = 0; while (disabledThreads < arrayThreads.Length) { diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs new file mode 100644 index 0000000..4aa360a --- /dev/null +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -0,0 +1,76 @@ +namespace TestsForMyThreadPool; + +using MyThreadPool; + +public class Tests +{ + [Test] + public void ATestWithOneTaskForTenThreads() + { + var myThreadPool = new MyThreadPool(10); + var task = myThreadPool.Submit(() => 2 * 2); + Assert.That(4, Is.EqualTo(task.Result)); + } + + [Test] + public void ATestWithTwoTasksForTenThreads() + { + var myThreadPool = new MyThreadPool(10); + var firstTask = myThreadPool.Submit(() => 2 * 2); + var secondTask = myThreadPool.Submit(() => 3 + 3); + Assert.That(4, Is.EqualTo(firstTask.Result)); + Assert.That(6, Is.EqualTo(secondTask.Result)); + } + + [Test] + public void WhenThereAreFewerThreadsThanTasks() + { + var myThreadPool = new MyThreadPool(1); + var firstTask = myThreadPool.Submit(() => 2 * 2); + var secondTask = myThreadPool.Submit(() => 3 + 3); + Assert.That(4, Is.EqualTo(firstTask.Result)); + Assert.That(6, Is.EqualTo(secondTask.Result)); + } + + [Test] + public void IsShutdownWorkingCorrectlyWithOneThread() + { + var token = new CancellationToken(); + var myThreadPool = new MyThreadPool(1); + var firstTask = myThreadPool.Submit(() => 2 * 2); + var secondTask = myThreadPool.Submit(() => 3 + 3); + token.ThrowIfCancellationRequested(); + myThreadPool.Shutdown(token); + Assert.That(4, Is.EqualTo(firstTask.Result)); + Assert.That(6, Is.EqualTo(secondTask.Result)); + } + + [Test] + public void IsShutdownWorkingCorrectlyWithMultipleThread() + { + var token = new CancellationToken(); + var myThreadPool = new MyThreadPool(3); + var firstTask = myThreadPool.Submit(() => 2 * 2); + var secondTask = myThreadPool.Submit(() => 3 + 3); + token.ThrowIfCancellationRequested(); + myThreadPool.Shutdown(token); + Assert.That(4, Is.EqualTo(firstTask.Result)); + Assert.That(6, Is.EqualTo(secondTask.Result)); + } + + [Test] + public void IsContinueWithWorkingCorrectlyWithWithOneSubtask() + { + var myThreadPool = new MyThreadPool(3); + var myTask = myThreadPool.Submit(() => 2 * 2).ContinueWith(x => x.ToString()); + Assert.That("4", Is.EqualTo(myTask.Result)); + } + + [Test] + public void IsContinueWithWorkingCorrectlyWithWithSeveralSubtask() + { + var myThreadPool = new MyThreadPool(3); + var myTask = myThreadPool.Submit(() => 2 * 2).ContinueWith(x => x * x).ContinueWith(x => x.ToString()); + Assert.That("16", Is.EqualTo(myTask.Result)); + } +} \ No newline at end of file diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.csproj b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.csproj new file mode 100644 index 0000000..c105e8f --- /dev/null +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.csproj @@ -0,0 +1,23 @@ + + + + net7.0 + enable + enable + + false + + + + + + + + + + + + + + + diff --git a/MyThreadPool/TestsForMyThreadPool/Usings.cs b/MyThreadPool/TestsForMyThreadPool/Usings.cs new file mode 100644 index 0000000..cefced4 --- /dev/null +++ b/MyThreadPool/TestsForMyThreadPool/Usings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file From 340e4db968d58a65dcf537e804ecb95e0cff8c4e Mon Sep 17 00:00:00 2001 From: Artem Date: Fri, 6 Oct 2023 23:51:17 +0300 Subject: [PATCH 05/17] =?UTF-8?q?=D0=A0=D0=B5=D0=B2=D1=8C=D1=8E=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/MyTask.cs | 11 ++-- MyThreadPool/MyThreadPool/MyThread.cs | 51 +++++++++++++------ MyThreadPool/MyThreadPool/MyThreadPool.cs | 16 ++++-- .../TestsForMyThreadPool.cs | 26 +++++----- 4 files changed, 69 insertions(+), 35 deletions(-) diff --git a/MyThreadPool/MyThreadPool/MyTask.cs b/MyThreadPool/MyThreadPool/MyTask.cs index 0f2885a..dadd75a 100644 --- a/MyThreadPool/MyThreadPool/MyTask.cs +++ b/MyThreadPool/MyThreadPool/MyTask.cs @@ -11,24 +11,27 @@ public class MyTask : IMyTask private Queue queueWithContinueWithTasks; private MyThread[] arrayThreads; private Queue queueWithTasks; - private Object locker = new Object(); + private Object locker; + private volatile bool stopCount; /// /// Constructor for creating a task /// - public MyTask(Func suppiler, MyThread[] arrayThreads, Queue queueWithTasks) + public MyTask(Func suppiler, MyThread[] arrayThreads, Queue queueWithTasks, Object locker, bool stopCount) { this.suppiler = suppiler; queueWithContinueWithTasks = new (); this.arrayThreads = arrayThreads; this.queueWithTasks = queueWithTasks; + this.locker = locker; + this.stopCount = stopCount; } public TResult? Result { get { - while (!isCompleted) {} + while (!isCompleted && !stopCount) {} return result; } } @@ -66,7 +69,7 @@ public bool IsQueueEmpty() public IMyTask ContinueWith(Func suppiler) { - var newTask = new MyTask(() => suppiler(Result), arrayThreads, queueWithTasks); + var newTask = new MyTask(() => suppiler(Result), arrayThreads, queueWithTasks, locker, stopCount); lock(locker) { if (IsCompleted) diff --git a/MyThreadPool/MyThreadPool/MyThread.cs b/MyThreadPool/MyThreadPool/MyThread.cs index c52803b..124da43 100644 --- a/MyThreadPool/MyThreadPool/MyThread.cs +++ b/MyThreadPool/MyThreadPool/MyThread.cs @@ -9,18 +9,19 @@ public class MyThread private volatile bool isAlive = true; private Thread? thread; private volatile Queue tasks; - private Object locker = new Object(); + private Object locker; private CancellationToken token; /// /// Task-based custom thread constructor /// - public MyThread(Queue tasks, CancellationToken token) + public MyThread(Queue tasks, CancellationToken token, object locker) { - thread = new Thread(() => EternalCycle()); - thread.Start(); this.tasks = tasks; this.token = token; + this.locker = locker; + thread = new Thread(() => EternalCycle()); + thread.Start(); } /// @@ -39,27 +40,36 @@ private void EternalCycle() Action? task = null; while (isAlive) { - while (tasks.Count == 0) { } + while (tasks.Count == 0 && isAlive) { } if (token.IsCancellationRequested) { break; } - lock (locker) - { - task = tasks.Dequeue(); - } - if (task != null) + if (isAlive) { - isActive = true; - try - { - task(); + lock (locker) + { + if (tasks.Count != 0) + { + task = tasks.Dequeue(); + } + isActive = true; } - catch (Exception ex) + if (task != null) { - throw new AggregateException(ex); + isActive = true; + try + { + task(); + } + catch (Exception ex) + { + throw new AggregateException(ex); + } + isActive = false; } isActive = false; + task = null; } } } @@ -79,4 +89,13 @@ public bool IsAlive() { return isAlive; } + + /// + /// Suspends the current thread + /// + public void Join() + { + while (thread.IsAlive) { } + thread.Join(); + } } diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index 3c2c16e..4a99243 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -7,13 +7,18 @@ public class MyThreadPool { private static MyThread[]? arrayThreads; private static Queue tasks = new (); - private CancellationToken token = new CancellationToken(); + private CancellationToken token = new (); + private Object lockerForThreads; + private Object lockerForTasks; + private volatile bool stopCount = false; /// /// Constructor for creating n number of threads for tasks /// public MyThreadPool(int sizeThreads) { + lockerForThreads = new (); + lockerForTasks = new (); if (sizeThreads <= 0) { throw new ArgumentOutOfRangeException(); @@ -21,7 +26,7 @@ public MyThreadPool(int sizeThreads) arrayThreads = new MyThread[sizeThreads]; for (int i = 0; i < sizeThreads; i++) { - arrayThreads[i] = new MyThread(tasks, token); + arrayThreads[i] = new(tasks, token, lockerForThreads); } } @@ -30,7 +35,7 @@ public MyThreadPool(int sizeThreads) /// public IMyTask Submit(Func suppiler) { - var newTask = new MyTask(suppiler, arrayThreads, tasks); + var newTask = new MyTask(suppiler, arrayThreads, tasks, lockerForTasks, stopCount); tasks.Enqueue(() => newTask.StartSuppiler()); return newTask; } @@ -56,5 +61,10 @@ public void Shutdown(CancellationToken tokenFromUser) } } } + foreach(var thread in arrayThreads) + { + thread.Join(); + } + stopCount = true; } } \ No newline at end of file diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index 4aa360a..714c8aa 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -3,46 +3,42 @@ namespace TestsForMyThreadPool; using MyThreadPool; public class Tests -{ +{ [Test] public void ATestWithOneTaskForTenThreads() { + var token = new CancellationToken(); var myThreadPool = new MyThreadPool(10); var task = myThreadPool.Submit(() => 2 * 2); Assert.That(4, Is.EqualTo(task.Result)); + token.ThrowIfCancellationRequested(); + myThreadPool.Shutdown(token); } [Test] public void ATestWithTwoTasksForTenThreads() { + var token = new CancellationToken(); var myThreadPool = new MyThreadPool(10); var firstTask = myThreadPool.Submit(() => 2 * 2); var secondTask = myThreadPool.Submit(() => 3 + 3); Assert.That(4, Is.EqualTo(firstTask.Result)); Assert.That(6, Is.EqualTo(secondTask.Result)); + token.ThrowIfCancellationRequested(); + myThreadPool.Shutdown(token); } [Test] public void WhenThereAreFewerThreadsThanTasks() { + var token = new CancellationToken(); var myThreadPool = new MyThreadPool(1); var firstTask = myThreadPool.Submit(() => 2 * 2); var secondTask = myThreadPool.Submit(() => 3 + 3); Assert.That(4, Is.EqualTo(firstTask.Result)); Assert.That(6, Is.EqualTo(secondTask.Result)); - } - - [Test] - public void IsShutdownWorkingCorrectlyWithOneThread() - { - var token = new CancellationToken(); - var myThreadPool = new MyThreadPool(1); - var firstTask = myThreadPool.Submit(() => 2 * 2); - var secondTask = myThreadPool.Submit(() => 3 + 3); token.ThrowIfCancellationRequested(); myThreadPool.Shutdown(token); - Assert.That(4, Is.EqualTo(firstTask.Result)); - Assert.That(6, Is.EqualTo(secondTask.Result)); } [Test] @@ -61,16 +57,22 @@ public void IsShutdownWorkingCorrectlyWithMultipleThread() [Test] public void IsContinueWithWorkingCorrectlyWithWithOneSubtask() { + var token = new CancellationToken(); var myThreadPool = new MyThreadPool(3); var myTask = myThreadPool.Submit(() => 2 * 2).ContinueWith(x => x.ToString()); Assert.That("4", Is.EqualTo(myTask.Result)); + token.ThrowIfCancellationRequested(); + myThreadPool.Shutdown(token); } [Test] public void IsContinueWithWorkingCorrectlyWithWithSeveralSubtask() { + var token = new CancellationToken(); var myThreadPool = new MyThreadPool(3); var myTask = myThreadPool.Submit(() => 2 * 2).ContinueWith(x => x * x).ContinueWith(x => x.ToString()); Assert.That("16", Is.EqualTo(myTask.Result)); + token.ThrowIfCancellationRequested(); + myThreadPool.Shutdown(token); } } \ No newline at end of file From 5ae1492e8b96bd54b4fe5b9db4294731a33cb505 Mon Sep 17 00:00:00 2001 From: Artem Date: Fri, 6 Oct 2023 23:58:33 +0300 Subject: [PATCH 06/17] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20.csproj?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/MyThreadPool.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.csproj b/MyThreadPool/MyThreadPool/MyThreadPool.csproj index f02677b..424caff 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.csproj +++ b/MyThreadPool/MyThreadPool/MyThreadPool.csproj @@ -5,6 +5,7 @@ net7.0 enable enable + Library From 1cdf7c770c435e9a10f2475d02aa9fa75195644f Mon Sep 17 00:00:00 2001 From: Artem Date: Sat, 7 Oct 2023 00:57:38 +0300 Subject: [PATCH 07/17] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B2=D0=BE=D0=B3=D0=BE=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/MyThreadPool.cs | 8 ++++---- MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index 4a99243..5295a5f 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -61,10 +61,10 @@ public void Shutdown(CancellationToken tokenFromUser) } } } - foreach(var thread in arrayThreads) - { - thread.Join(); - } + //foreach(var thread in arrayThreads) + //{ + // thread.Join(); + //} stopCount = true; } } \ No newline at end of file diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index 714c8aa..3ff8d42 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -15,6 +15,7 @@ public void ATestWithOneTaskForTenThreads() myThreadPool.Shutdown(token); } + /* [Test] public void ATestWithTwoTasksForTenThreads() { @@ -75,4 +76,5 @@ public void IsContinueWithWorkingCorrectlyWithWithSeveralSubtask() token.ThrowIfCancellationRequested(); myThreadPool.Shutdown(token); } + */ } \ No newline at end of file From b5059ad20dc6755e9a73e3e7898b0f4daebe7679 Mon Sep 17 00:00:00 2001 From: Artem Date: Sat, 7 Oct 2023 01:04:42 +0300 Subject: [PATCH 08/17] =?UTF-8?q?=D0=92=D1=81=D0=B5=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/MyThreadPool.cs | 8 ++++---- MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index 5295a5f..4a99243 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -61,10 +61,10 @@ public void Shutdown(CancellationToken tokenFromUser) } } } - //foreach(var thread in arrayThreads) - //{ - // thread.Join(); - //} + foreach(var thread in arrayThreads) + { + thread.Join(); + } stopCount = true; } } \ No newline at end of file diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index 3ff8d42..714c8aa 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -15,7 +15,6 @@ public void ATestWithOneTaskForTenThreads() myThreadPool.Shutdown(token); } - /* [Test] public void ATestWithTwoTasksForTenThreads() { @@ -76,5 +75,4 @@ public void IsContinueWithWorkingCorrectlyWithWithSeveralSubtask() token.ThrowIfCancellationRequested(); myThreadPool.Shutdown(token); } - */ } \ No newline at end of file From 2fb9b31f60b8d8ad2c56b9bb51d7526a71c60619 Mon Sep 17 00:00:00 2001 From: Artem Date: Sat, 7 Oct 2023 14:47:35 +0300 Subject: [PATCH 09/17] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=8B=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=82=D0=B5=D1=81=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/MyTask.cs | 6 ++++-- MyThreadPool/MyThreadPool/MyThread.cs | 8 +++++--- MyThreadPool/MyThreadPool/MyThreadPool.cs | 8 ++++---- .../TestsForMyThreadPool.cs | 17 ++++++++++++++++- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/MyThreadPool/MyThreadPool/MyTask.cs b/MyThreadPool/MyThreadPool/MyTask.cs index dadd75a..594c3ee 100644 --- a/MyThreadPool/MyThreadPool/MyTask.cs +++ b/MyThreadPool/MyThreadPool/MyTask.cs @@ -1,4 +1,6 @@ -namespace MyThreadPool; +using System.Diagnostics; + +namespace MyThreadPool; /// /// A class for creating tasks @@ -20,7 +22,7 @@ public class MyTask : IMyTask public MyTask(Func suppiler, MyThread[] arrayThreads, Queue queueWithTasks, Object locker, bool stopCount) { this.suppiler = suppiler; - queueWithContinueWithTasks = new (); + queueWithContinueWithTasks = new(); this.arrayThreads = arrayThreads; this.queueWithTasks = queueWithTasks; this.locker = locker; diff --git a/MyThreadPool/MyThreadPool/MyThread.cs b/MyThreadPool/MyThreadPool/MyThread.cs index 124da43..41cd546 100644 --- a/MyThreadPool/MyThreadPool/MyThread.cs +++ b/MyThreadPool/MyThreadPool/MyThread.cs @@ -1,4 +1,6 @@ -namespace MyThreadPool; +using System.Diagnostics; + +namespace MyThreadPool; /// /// A class of native threads responsible for executing tasks @@ -51,7 +53,7 @@ private void EternalCycle() { if (tasks.Count != 0) { - task = tasks.Dequeue(); + tasks.TryDequeue(out task); } isActive = true; } @@ -95,7 +97,7 @@ public bool IsAlive() /// public void Join() { - while (thread.IsAlive) { } + while (isAlive) { } thread.Join(); } } diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index 4a99243..76a24fd 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -6,8 +6,8 @@ public class MyThreadPool { private static MyThread[]? arrayThreads; - private static Queue tasks = new (); - private CancellationToken token = new (); + private static Queue tasks = new(); + private CancellationToken token = new(); private Object lockerForThreads; private Object lockerForTasks; private volatile bool stopCount = false; @@ -17,8 +17,8 @@ public class MyThreadPool /// public MyThreadPool(int sizeThreads) { - lockerForThreads = new (); - lockerForTasks = new (); + lockerForThreads = new(); + lockerForTasks = new(); if (sizeThreads <= 0) { throw new ArgumentOutOfRangeException(); diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index 714c8aa..88e13b9 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -3,7 +3,20 @@ namespace TestsForMyThreadPool; using MyThreadPool; public class Tests -{ +{ + [Test] + public void IsShutdownWorkingCorrectlyWithOneThread() + { + var token = new CancellationToken(); + var myThreadPool = new MyThreadPool(1); + var firstTask = myThreadPool.Submit(() => 2 * 2); + var secondTask = myThreadPool.Submit(() => 3 + 3); + token.ThrowIfCancellationRequested(); + myThreadPool.Shutdown(token); + Assert.That(4, Is.EqualTo(firstTask.Result)); + Assert.That(6, Is.EqualTo(secondTask.Result)); + } + [Test] public void ATestWithOneTaskForTenThreads() { @@ -15,6 +28,7 @@ public void ATestWithOneTaskForTenThreads() myThreadPool.Shutdown(token); } + /* [Test] public void ATestWithTwoTasksForTenThreads() { @@ -75,4 +89,5 @@ public void IsContinueWithWorkingCorrectlyWithWithSeveralSubtask() token.ThrowIfCancellationRequested(); myThreadPool.Shutdown(token); } + */ } \ No newline at end of file From b442b2af51f4ea5ce54ddedce016ba319e98b131 Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 9 Oct 2023 19:31:56 +0300 Subject: [PATCH 10/17] =?UTF-8?q?=D0=9A=D0=B0=D1=87=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B2=D0=B5=D0=BD=D0=BD=D0=BE=D0=B5=20=D1=83=D0=BB=D1=83=D1=87?= =?UTF-8?q?=D1=88=D0=B5=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/MyTask.cs | 20 +++---- MyThreadPool/MyThreadPool/MyThread.cs | 49 ++++++++-------- MyThreadPool/MyThreadPool/MyThreadPool.cs | 42 +++++++------- .../TestsForMyThreadPool.cs | 57 +++++-------------- 4 files changed, 73 insertions(+), 95 deletions(-) diff --git a/MyThreadPool/MyThreadPool/MyTask.cs b/MyThreadPool/MyThreadPool/MyTask.cs index 594c3ee..3a41727 100644 --- a/MyThreadPool/MyThreadPool/MyTask.cs +++ b/MyThreadPool/MyThreadPool/MyTask.cs @@ -7,33 +7,33 @@ namespace MyThreadPool; /// public class MyTask : IMyTask { - private Func? suppiler; + private readonly Func? suppiler; private volatile bool isCompleted = false; private TResult? result; - private Queue queueWithContinueWithTasks; - private MyThread[] arrayThreads; - private Queue queueWithTasks; - private Object locker; - private volatile bool stopCount; + private readonly Queue queueWithContinueWithTasks; + private readonly MyThread[] arrayThreads; + private readonly Queue queueWithTasks; + private readonly Object locker; + private CancellationTokenSource token; /// /// Constructor for creating a task /// - public MyTask(Func suppiler, MyThread[] arrayThreads, Queue queueWithTasks, Object locker, bool stopCount) + public MyTask(Func suppiler, MyThread[] arrayThreads, Queue queueWithTasks, Object locker, CancellationTokenSource token) { this.suppiler = suppiler; queueWithContinueWithTasks = new(); this.arrayThreads = arrayThreads; this.queueWithTasks = queueWithTasks; this.locker = locker; - this.stopCount = stopCount; + this.token = token; } public TResult? Result { get { - while (!isCompleted && !stopCount) {} + while (!isCompleted && !token.IsCancellationRequested) {} return result; } } @@ -71,7 +71,7 @@ public bool IsQueueEmpty() public IMyTask ContinueWith(Func suppiler) { - var newTask = new MyTask(() => suppiler(Result), arrayThreads, queueWithTasks, locker, stopCount); + var newTask = new MyTask(() => suppiler(Result), arrayThreads, queueWithTasks, locker, token); lock(locker) { if (IsCompleted) diff --git a/MyThreadPool/MyThreadPool/MyThread.cs b/MyThreadPool/MyThreadPool/MyThread.cs index 41cd546..749427b 100644 --- a/MyThreadPool/MyThreadPool/MyThread.cs +++ b/MyThreadPool/MyThreadPool/MyThread.cs @@ -8,21 +8,21 @@ namespace MyThreadPool; public class MyThread { private volatile bool isActive = false; - private volatile bool isAlive = true; private Thread? thread; private volatile Queue tasks; + private volatile bool isAlive = true; private Object locker; - private CancellationToken token; + private CancellationTokenSource token; /// /// Task-based custom thread constructor /// - public MyThread(Queue tasks, CancellationToken token, object locker) + public MyThread(Queue tasks, CancellationTokenSource token, object locker) { this.tasks = tasks; this.token = token; this.locker = locker; - thread = new Thread(() => EternalCycle()); + thread = new Thread(EternalCycle); thread.Start(); } @@ -40,15 +40,18 @@ public bool IsActive() private void EternalCycle() { Action? task = null; - while (isAlive) + while (!token.IsCancellationRequested) { - while (tasks.Count == 0 && isAlive) { } - if (token.IsCancellationRequested) - { - break; - } - if (isAlive) + while (!(tasks.Count == 0)) { + if (token.IsCancellationRequested) + { + lock (locker) + { + isAlive = false; + return; + } + } lock (locker) { if (tasks.Count != 0) @@ -74,20 +77,14 @@ private void EternalCycle() task = null; } } + lock (locker) + { + isAlive = false; + return; + } } - /// - /// Eliminating threads - /// - public void KillThread() - { - isAlive = false; - } - - /// - /// Checking whether the thread is alive - /// - public bool IsAlive() + public bool GetIsAlive() { return isAlive; } @@ -97,7 +94,11 @@ public bool IsAlive() /// public void Join() { - while (isAlive) { } + if (thread == null) + { + throw new ArgumentNullException(nameof(thread)); + } + thread.Join(); } } diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index 76a24fd..51ce023 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -5,11 +5,11 @@ /// public class MyThreadPool { - private static MyThread[]? arrayThreads; - private static Queue tasks = new(); - private CancellationToken token = new(); - private Object lockerForThreads; - private Object lockerForTasks; + private readonly MyThread[]? arrayThreads; + private readonly Queue tasks = new(); + private readonly CancellationTokenSource token = new(); + private readonly Object lockerForThreads; + private readonly Object lockerForTasks; private volatile bool stopCount = false; /// @@ -35,7 +35,11 @@ public MyThreadPool(int sizeThreads) /// public IMyTask Submit(Func suppiler) { - var newTask = new MyTask(suppiler, arrayThreads, tasks, lockerForTasks, stopCount); + if (arrayThreads == null) + { + throw new ArgumentNullException(); + } + var newTask = new MyTask(suppiler, arrayThreads, tasks, lockerForTasks, token); tasks.Enqueue(() => newTask.StartSuppiler()); return newTask; } @@ -43,24 +47,24 @@ public IMyTask Submit(Func suppiler) /// /// Interrupts the processing of tasks that are not started do not begin, and those that are started are being completed /// - public void Shutdown(CancellationToken tokenFromUser) + public void Shutdown() { - if (tokenFromUser.IsCancellationRequested) + if (arrayThreads == null) + { + throw new ArgumentNullException(nameof(arrayThreads)); + } + token.Cancel(); + + if (token.IsCancellationRequested) { - token.ThrowIfCancellationRequested(); + ; } - int disabledThreads = 0; - while (disabledThreads < arrayThreads.Length) + + for (int i = 0; i < arrayThreads.Length; ++i) { - for (int i = 0; i < arrayThreads.Length; ++i) - { - if (arrayThreads[i].IsAlive() && !arrayThreads[i].IsActive()) - { - arrayThreads[i].KillThread(); - ++disabledThreads; - } - } + while (arrayThreads[i].GetIsAlive()) {} } + foreach(var thread in arrayThreads) { thread.Join(); diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index 88e13b9..f261e21 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -4,90 +4,63 @@ namespace TestsForMyThreadPool; public class Tests { - [Test] - public void IsShutdownWorkingCorrectlyWithOneThread() - { - var token = new CancellationToken(); - var myThreadPool = new MyThreadPool(1); - var firstTask = myThreadPool.Submit(() => 2 * 2); - var secondTask = myThreadPool.Submit(() => 3 + 3); - token.ThrowIfCancellationRequested(); - myThreadPool.Shutdown(token); - Assert.That(4, Is.EqualTo(firstTask.Result)); - Assert.That(6, Is.EqualTo(secondTask.Result)); - } - [Test] public void ATestWithOneTaskForTenThreads() { - var token = new CancellationToken(); var myThreadPool = new MyThreadPool(10); var task = myThreadPool.Submit(() => 2 * 2); - Assert.That(4, Is.EqualTo(task.Result)); - token.ThrowIfCancellationRequested(); - myThreadPool.Shutdown(token); + Assert.That(Equals(task.Result, 4)); + myThreadPool.Shutdown(); } - /* [Test] public void ATestWithTwoTasksForTenThreads() { - var token = new CancellationToken(); var myThreadPool = new MyThreadPool(10); var firstTask = myThreadPool.Submit(() => 2 * 2); var secondTask = myThreadPool.Submit(() => 3 + 3); - Assert.That(4, Is.EqualTo(firstTask.Result)); - Assert.That(6, Is.EqualTo(secondTask.Result)); - token.ThrowIfCancellationRequested(); - myThreadPool.Shutdown(token); + Assert.That(Equals(firstTask.Result, 4)); + Assert.That(Equals(secondTask.Result, 6)); + myThreadPool.Shutdown(); } [Test] public void WhenThereAreFewerThreadsThanTasks() { - var token = new CancellationToken(); var myThreadPool = new MyThreadPool(1); var firstTask = myThreadPool.Submit(() => 2 * 2); var secondTask = myThreadPool.Submit(() => 3 + 3); - Assert.That(4, Is.EqualTo(firstTask.Result)); - Assert.That(6, Is.EqualTo(secondTask.Result)); - token.ThrowIfCancellationRequested(); - myThreadPool.Shutdown(token); + Assert.That(Equals(firstTask.Result, 4)); + Assert.That(Equals(secondTask.Result, 6)); + myThreadPool.Shutdown(); } [Test] public void IsShutdownWorkingCorrectlyWithMultipleThread() { - var token = new CancellationToken(); var myThreadPool = new MyThreadPool(3); var firstTask = myThreadPool.Submit(() => 2 * 2); var secondTask = myThreadPool.Submit(() => 3 + 3); - token.ThrowIfCancellationRequested(); - myThreadPool.Shutdown(token); - Assert.That(4, Is.EqualTo(firstTask.Result)); - Assert.That(6, Is.EqualTo(secondTask.Result)); + myThreadPool.Shutdown(); + Assert.That(Equals(firstTask.Result, 4)); + Assert.That(Equals(secondTask.Result, 6)); } [Test] public void IsContinueWithWorkingCorrectlyWithWithOneSubtask() { - var token = new CancellationToken(); var myThreadPool = new MyThreadPool(3); var myTask = myThreadPool.Submit(() => 2 * 2).ContinueWith(x => x.ToString()); - Assert.That("4", Is.EqualTo(myTask.Result)); - token.ThrowIfCancellationRequested(); - myThreadPool.Shutdown(token); + Assert.That(Equals(myTask.Result, "4")); + myThreadPool.Shutdown(); } [Test] public void IsContinueWithWorkingCorrectlyWithWithSeveralSubtask() { - var token = new CancellationToken(); var myThreadPool = new MyThreadPool(3); var myTask = myThreadPool.Submit(() => 2 * 2).ContinueWith(x => x * x).ContinueWith(x => x.ToString()); - Assert.That("16", Is.EqualTo(myTask.Result)); - token.ThrowIfCancellationRequested(); - myThreadPool.Shutdown(token); + Assert.That(Equals(myTask.Result, "16")); + myThreadPool.Shutdown(); } - */ } \ No newline at end of file From 82702d597df572e383ca2154962ea9102ff1321c Mon Sep 17 00:00:00 2001 From: Artem Date: Mon, 9 Oct 2023 19:54:32 +0300 Subject: [PATCH 11/17] =?UTF-8?q?=D0=A2=D0=B5=D1=81=D1=82=20=D0=BD=D0=B0?= =?UTF-8?q?=20=D1=80=D0=B0=D0=B7=D0=BD=D1=8B=D1=85=20=D1=83=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=BE=D0=B9=D1=81=D1=82=D0=B2=D0=B0=D1=85=20=D1=81=D0=BF?= =?UTF-8?q?=D0=BE=D1=81=D0=BE=D0=B1=D0=B5=D0=BD=20=D0=B4=D0=B0=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D1=80=D0=B0=D0=B7=D0=BD=D1=8B=D0=B9=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B7=D1=83=D0=BB=D1=8C=D1=82=D0=B0=D1=82,=20=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=BF=D0=BE=D0=B4=D1=85=D0=BE=D0=B4=D0=B8=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TestsForMyThreadPool/TestsForMyThreadPool.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index f261e21..fd443aa 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -35,17 +35,6 @@ public void WhenThereAreFewerThreadsThanTasks() myThreadPool.Shutdown(); } - [Test] - public void IsShutdownWorkingCorrectlyWithMultipleThread() - { - var myThreadPool = new MyThreadPool(3); - var firstTask = myThreadPool.Submit(() => 2 * 2); - var secondTask = myThreadPool.Submit(() => 3 + 3); - myThreadPool.Shutdown(); - Assert.That(Equals(firstTask.Result, 4)); - Assert.That(Equals(secondTask.Result, 6)); - } - [Test] public void IsContinueWithWorkingCorrectlyWithWithOneSubtask() { From 5bd3f9a7fe8b8e6536a9b48145c9468e37303d65 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 10 Dec 2023 12:27:43 +0300 Subject: [PATCH 12/17] =?UTF-8?q?=D0=A0=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/IMyTask.cs | 8 +- MyThreadPool/MyThreadPool/MyTask.cs | 88 -------- MyThreadPool/MyThreadPool/MyThread.cs | 104 --------- MyThreadPool/MyThreadPool/MyThreadPool.cs | 202 ++++++++++++++++-- .../MyThreadPool/ShudownWasThrownException.cs | 13 ++ .../TestsForMyThreadPool.cs | 59 ++++- 6 files changed, 260 insertions(+), 214 deletions(-) delete mode 100644 MyThreadPool/MyThreadPool/MyTask.cs delete mode 100644 MyThreadPool/MyThreadPool/MyThread.cs create mode 100644 MyThreadPool/MyThreadPool/ShudownWasThrownException.cs diff --git a/MyThreadPool/MyThreadPool/IMyTask.cs b/MyThreadPool/MyThreadPool/IMyTask.cs index 18e1e74..19da006 100644 --- a/MyThreadPool/MyThreadPool/IMyTask.cs +++ b/MyThreadPool/MyThreadPool/IMyTask.cs @@ -5,10 +5,16 @@ /// public interface IMyTask { + /// + /// Check is completed Task and return result + /// public bool IsCompleted { get; } + /// + /// Return Result Task + /// public TResult? Result { get; } /// /// A method for solving subtasks from the results obtained from the tasks /// - public IMyTask ContinueWith(Func suppiler); + public IMyTask ContinueWith(Func supplier); } \ No newline at end of file diff --git a/MyThreadPool/MyThreadPool/MyTask.cs b/MyThreadPool/MyThreadPool/MyTask.cs deleted file mode 100644 index 3a41727..0000000 --- a/MyThreadPool/MyThreadPool/MyTask.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Diagnostics; - -namespace MyThreadPool; - -/// -/// A class for creating tasks -/// -public class MyTask : IMyTask -{ - private readonly Func? suppiler; - private volatile bool isCompleted = false; - private TResult? result; - private readonly Queue queueWithContinueWithTasks; - private readonly MyThread[] arrayThreads; - private readonly Queue queueWithTasks; - private readonly Object locker; - private CancellationTokenSource token; - - /// - /// Constructor for creating a task - /// - public MyTask(Func suppiler, MyThread[] arrayThreads, Queue queueWithTasks, Object locker, CancellationTokenSource token) - { - this.suppiler = suppiler; - queueWithContinueWithTasks = new(); - this.arrayThreads = arrayThreads; - this.queueWithTasks = queueWithTasks; - this.locker = locker; - this.token = token; - } - - public TResult? Result - { - get - { - while (!isCompleted && !token.IsCancellationRequested) {} - return result; - } - } - public bool IsCompleted - { - get - { - return isCompleted; - } - } - - /// - /// Task completion - /// - public void StartSuppiler() - { - if (suppiler != null) - { - result = suppiler(); - isCompleted = true; - while (queueWithContinueWithTasks.Count > 0) - { - queueWithTasks.Enqueue(queueWithContinueWithTasks.Dequeue()); - } - } - } - - /// - /// Checking that the task queue is empty - /// - public bool IsQueueEmpty() - { - return queueWithContinueWithTasks.Count == 0; - } - - public IMyTask ContinueWith(Func suppiler) - { - var newTask = new MyTask(() => suppiler(Result), arrayThreads, queueWithTasks, locker, token); - lock(locker) - { - if (IsCompleted) - { - queueWithTasks.Enqueue(() => newTask.StartSuppiler()); - } - else - { - queueWithContinueWithTasks.Enqueue(() => newTask.StartSuppiler()); - } - } - return newTask; - } -} \ No newline at end of file diff --git a/MyThreadPool/MyThreadPool/MyThread.cs b/MyThreadPool/MyThreadPool/MyThread.cs deleted file mode 100644 index 749427b..0000000 --- a/MyThreadPool/MyThreadPool/MyThread.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System.Diagnostics; - -namespace MyThreadPool; - -/// -/// A class of native threads responsible for executing tasks -/// -public class MyThread -{ - private volatile bool isActive = false; - private Thread? thread; - private volatile Queue tasks; - private volatile bool isAlive = true; - private Object locker; - private CancellationTokenSource token; - - /// - /// Task-based custom thread constructor - /// - public MyThread(Queue tasks, CancellationTokenSource token, object locker) - { - this.tasks = tasks; - this.token = token; - this.locker = locker; - thread = new Thread(EternalCycle); - thread.Start(); - } - - /// - /// Checks if the thread is busy - /// - public bool IsActive() - { - return isActive; - } - - /// - /// Task waiting cycle - /// - private void EternalCycle() - { - Action? task = null; - while (!token.IsCancellationRequested) - { - while (!(tasks.Count == 0)) - { - if (token.IsCancellationRequested) - { - lock (locker) - { - isAlive = false; - return; - } - } - lock (locker) - { - if (tasks.Count != 0) - { - tasks.TryDequeue(out task); - } - isActive = true; - } - if (task != null) - { - isActive = true; - try - { - task(); - } - catch (Exception ex) - { - throw new AggregateException(ex); - } - isActive = false; - } - isActive = false; - task = null; - } - } - lock (locker) - { - isAlive = false; - return; - } - } - - public bool GetIsAlive() - { - return isAlive; - } - - /// - /// Suspends the current thread - /// - public void Join() - { - if (thread == null) - { - throw new ArgumentNullException(nameof(thread)); - } - - thread.Join(); - } -} diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index 51ce023..bfe7400 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -9,8 +9,7 @@ public class MyThreadPool private readonly Queue tasks = new(); private readonly CancellationTokenSource token = new(); private readonly Object lockerForThreads; - private readonly Object lockerForTasks; - private volatile bool stopCount = false; + private EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); /// /// Constructor for creating n number of threads for tasks @@ -18,7 +17,6 @@ public class MyThreadPool public MyThreadPool(int sizeThreads) { lockerForThreads = new(); - lockerForTasks = new(); if (sizeThreads <= 0) { throw new ArgumentOutOfRangeException(); @@ -26,21 +24,39 @@ public MyThreadPool(int sizeThreads) arrayThreads = new MyThread[sizeThreads]; for (int i = 0; i < sizeThreads; i++) { - arrayThreads[i] = new(tasks, token, lockerForThreads); + arrayThreads[i] = new(tasks, token.Token, lockerForThreads, waitHandle); } } + /// + /// Get number of threads + /// + public int GetNumberOfThreads() + { + if (arrayThreads == null) + { + throw new ArgumentNullException(); + } + return arrayThreads.Length; + } + /// /// Accepts a function, adds it as a task in the thread, and returns the created task /// - public IMyTask Submit(Func suppiler) + public IMyTask Submit(Func supplier) { + if (token.IsCancellationRequested) + { + throw new ShudownWasThrownException(); + } if (arrayThreads == null) { throw new ArgumentNullException(); } - var newTask = new MyTask(suppiler, arrayThreads, tasks, lockerForTasks, token); - tasks.Enqueue(() => newTask.StartSuppiler()); + var newTask = new MyTask(supplier, token, this); + tasks.Enqueue(() => newTask.StartSupplier()); + waitHandle.Set(); + return newTask; } @@ -53,22 +69,180 @@ public void Shutdown() { throw new ArgumentNullException(nameof(arrayThreads)); } + token.Cancel(); - - if (token.IsCancellationRequested) + waitHandle.Set(); + + foreach(var thread in arrayThreads) { - ; + thread.Join(); } + } - for (int i = 0; i < arrayThreads.Length; ++i) + private class MyThread + { + private Thread? thread; + private volatile Queue tasks; + private Object locker; + private CancellationToken token; + private EventWaitHandle? waitHandle; + + /// + /// Task-based custom thread constructor + /// + public MyThread(Queue tasks, CancellationToken token, object locker, EventWaitHandle? waitHandle) { - while (arrayThreads[i].GetIsAlive()) {} + this.tasks = tasks; + this.token = token; + this.locker = locker; + thread = new Thread(EternalCycle); + thread.Start(); + this.waitHandle = waitHandle; } - foreach(var thread in arrayThreads) + /// + /// Task waiting cycle + /// + private void EternalCycle() { + if (waitHandle == null) + { + throw new NullReferenceException(); + } + Action? task = null; + while (!token.IsCancellationRequested) + { + waitHandle.WaitOne(); + if (!token.IsCancellationRequested) + { + lock (locker) + { + if (tasks.Count != 0) + { + var isCorrect = tasks.TryDequeue(out task); + if (!isCorrect) + { + throw new InvalidOperationException(); + } + } + if (tasks.Count == 0) + { + waitHandle.Reset(); + } + } + if (task != null) + { + task(); + } + task = null; + if (token.IsCancellationRequested) + { + return; + } + } + } + } + + /// + /// Suspends the current thread + /// + public void Join() + { + if (thread == null) + { + throw new ArgumentNullException(nameof(thread)); + } + thread.Join(); } - stopCount = true; + } + + private class MyTask : IMyTask + { + private readonly Func? supplier; + private TResult? result; + private Exception? exception; + private CancellationTokenSource token; + private EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); + private MyThreadPool? pool; + + /// + /// Constructor for creating a task + /// + public MyTask(Func supplier, CancellationTokenSource token, MyThreadPool pool) + { + this.supplier = supplier; + this.token = token; + this.pool = pool; + } + + /// + /// Get Result + /// + public TResult? Result + { + get + { + if (waitHandle == null) + { + throw new InvalidOperationException(); + } + waitHandle.WaitOne(); + if (exception != null) + { + throw new AggregateException(exception); + } + return result; + } + } + + /// + /// Check is completed Task and return result + /// + public bool IsCompleted { get; private set; } + + /// + /// Task completion + /// + public void StartSupplier() + { + if (supplier != null) + { + try + { + result = supplier(); + } + catch (Exception ex) + { + exception = ex; + } + + if (waitHandle == null) + { + throw new InvalidOperationException(); + } + + waitHandle.Set(); + + IsCompleted = true; + } + } + + /// + /// A method for solving subtasks from the results obtained from the tasks + /// + public IMyTask ContinueWith(Func supplier) + { + if (pool == null) + { + throw new InvalidOperationException(); + } + + if (!token.IsCancellationRequested) + { + return pool.Submit(() => supplier(Result)); + } + throw new ShudownWasThrownException(); + } } } \ No newline at end of file diff --git a/MyThreadPool/MyThreadPool/ShudownWasThrownException.cs b/MyThreadPool/MyThreadPool/ShudownWasThrownException.cs new file mode 100644 index 0000000..656a70c --- /dev/null +++ b/MyThreadPool/MyThreadPool/ShudownWasThrownException.cs @@ -0,0 +1,13 @@ +namespace MyThreadPool; + +/// +/// An exception is thrown if, after calling the Shutdown method, the user calls other methods +/// +public class ShudownWasThrownException : Exception +{ + public ShudownWasThrownException() { } + + public ShudownWasThrownException(string? message) : base(message) { } + + public ShudownWasThrownException(string? message, Exception? innerException) : base(message, innerException) { } +} \ No newline at end of file diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index fd443aa..ddc69ce 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -9,7 +9,7 @@ public void ATestWithOneTaskForTenThreads() { var myThreadPool = new MyThreadPool(10); var task = myThreadPool.Submit(() => 2 * 2); - Assert.That(Equals(task.Result, 4)); + Assert.That(task.Result, Is.EqualTo(4)); myThreadPool.Shutdown(); } @@ -19,8 +19,8 @@ public void ATestWithTwoTasksForTenThreads() var myThreadPool = new MyThreadPool(10); var firstTask = myThreadPool.Submit(() => 2 * 2); var secondTask = myThreadPool.Submit(() => 3 + 3); - Assert.That(Equals(firstTask.Result, 4)); - Assert.That(Equals(secondTask.Result, 6)); + Assert.That(firstTask.Result, Is.EqualTo(4)); + Assert.That(secondTask.Result, Is.EqualTo(6)); myThreadPool.Shutdown(); } @@ -30,8 +30,8 @@ public void WhenThereAreFewerThreadsThanTasks() var myThreadPool = new MyThreadPool(1); var firstTask = myThreadPool.Submit(() => 2 * 2); var secondTask = myThreadPool.Submit(() => 3 + 3); - Assert.That(Equals(firstTask.Result, 4)); - Assert.That(Equals(secondTask.Result, 6)); + Assert.That(firstTask.Result, Is.EqualTo(4)); + Assert.That(secondTask.Result, Is.EqualTo(6)); myThreadPool.Shutdown(); } @@ -40,7 +40,7 @@ public void IsContinueWithWorkingCorrectlyWithWithOneSubtask() { var myThreadPool = new MyThreadPool(3); var myTask = myThreadPool.Submit(() => 2 * 2).ContinueWith(x => x.ToString()); - Assert.That(Equals(myTask.Result, "4")); + Assert.That(myTask.Result, Is.EqualTo("4")); myThreadPool.Shutdown(); } @@ -49,7 +49,52 @@ public void IsContinueWithWorkingCorrectlyWithWithSeveralSubtask() { var myThreadPool = new MyThreadPool(3); var myTask = myThreadPool.Submit(() => 2 * 2).ContinueWith(x => x * x).ContinueWith(x => x.ToString()); - Assert.That(Equals(myTask.Result, "16")); + Assert.That(myTask.Result, Is.EqualTo("16")); myThreadPool.Shutdown(); } + + [Test] + public void NumberThreadsTheRequiredNumberIsCreated() + { + var myThreadPool = new MyThreadPool(5); + Assert.That(myThreadPool.GetNumberOfThreads(), Is.EqualTo(5)); + myThreadPool.Shutdown(); + } + + [Test] + public void WorkingWithException() + { + var myThreadPool = new MyThreadPool(10); + var task = myThreadPool.Submit(() => + { + int zero = 0; + return 1 / zero; + }); + Assert.Throws(() => { var result = task.Result;}); + myThreadPool.Shutdown(); + } + + [Test] + public void TheTaskWillCompletedWhenExceptionResult() + { + var myThreadPool = new MyThreadPool(10); + var task = myThreadPool.Submit(() => + { + int zero = 0; + return 1 / zero; + }); + Assert.Throws(() => { var result = task.Result; }); + Assert.That(task.IsCompleted, Is.True); + myThreadPool.Shutdown(); + } + + [Test] + public void AnotherTasksWillNotBeAcceptedAndTheOldOnesWillBeFinalized() + { + var myThreadPool = new MyThreadPool(1); + var firstTask = myThreadPool.Submit(() => 2 * 2); + myThreadPool.Shutdown(); + Assert.That(firstTask.Result, Is.EqualTo(4)); + Assert.Throws(() => { var secondTask = myThreadPool.Submit(() => 3 + 3); }); + } } \ No newline at end of file From c9b8fc6e00cdcf47eff9908461d8641ef9a98b02 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 10 Dec 2023 12:56:23 +0300 Subject: [PATCH 13/17] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index ddc69ce..655f537 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -13,6 +13,7 @@ public void ATestWithOneTaskForTenThreads() myThreadPool.Shutdown(); } + /* [Test] public void ATestWithTwoTasksForTenThreads() { @@ -97,4 +98,5 @@ public void AnotherTasksWillNotBeAcceptedAndTheOldOnesWillBeFinalized() Assert.That(firstTask.Result, Is.EqualTo(4)); Assert.Throws(() => { var secondTask = myThreadPool.Submit(() => 3 + 3); }); } + */ } \ No newline at end of file From f796dda5deda06badc1316209412bb4b7d6fc91a Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 10 Dec 2023 13:08:46 +0300 Subject: [PATCH 14/17] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=8B=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index 655f537..bb49f00 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -13,7 +13,6 @@ public void ATestWithOneTaskForTenThreads() myThreadPool.Shutdown(); } - /* [Test] public void ATestWithTwoTasksForTenThreads() { @@ -35,7 +34,7 @@ public void WhenThereAreFewerThreadsThanTasks() Assert.That(secondTask.Result, Is.EqualTo(6)); myThreadPool.Shutdown(); } - + [Test] public void IsContinueWithWorkingCorrectlyWithWithOneSubtask() { @@ -44,7 +43,7 @@ public void IsContinueWithWorkingCorrectlyWithWithOneSubtask() Assert.That(myTask.Result, Is.EqualTo("4")); myThreadPool.Shutdown(); } - + [Test] public void IsContinueWithWorkingCorrectlyWithWithSeveralSubtask() { @@ -98,5 +97,4 @@ public void AnotherTasksWillNotBeAcceptedAndTheOldOnesWillBeFinalized() Assert.That(firstTask.Result, Is.EqualTo(4)); Assert.Throws(() => { var secondTask = myThreadPool.Submit(() => 3 + 3); }); } - */ } \ No newline at end of file From a15879483e0fcea292a364651cc1a34b122485c4 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 10 Dec 2023 13:18:50 +0300 Subject: [PATCH 15/17] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=8B=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index bb49f00..03d7051 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -13,6 +13,7 @@ public void ATestWithOneTaskForTenThreads() myThreadPool.Shutdown(); } + /* [Test] public void ATestWithTwoTasksForTenThreads() { @@ -23,6 +24,7 @@ public void ATestWithTwoTasksForTenThreads() Assert.That(secondTask.Result, Is.EqualTo(6)); myThreadPool.Shutdown(); } + */ [Test] public void WhenThereAreFewerThreadsThanTasks() @@ -52,7 +54,8 @@ public void IsContinueWithWorkingCorrectlyWithWithSeveralSubtask() Assert.That(myTask.Result, Is.EqualTo("16")); myThreadPool.Shutdown(); } - + + /* [Test] public void NumberThreadsTheRequiredNumberIsCreated() { @@ -97,4 +100,5 @@ public void AnotherTasksWillNotBeAcceptedAndTheOldOnesWillBeFinalized() Assert.That(firstTask.Result, Is.EqualTo(4)); Assert.Throws(() => { var secondTask = myThreadPool.Submit(() => 3 + 3); }); } + */ } \ No newline at end of file From 2390068451e5d76c73eca3bf798e2cc5df4562a1 Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 10 Dec 2023 13:49:48 +0300 Subject: [PATCH 16/17] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=B0=204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/MyThreadPool.cs | 13 +++++-------- .../TestsForMyThreadPool/TestsForMyThreadPool.cs | 4 ---- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index bfe7400..ada682e 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -9,13 +9,14 @@ public class MyThreadPool private readonly Queue tasks = new(); private readonly CancellationTokenSource token = new(); private readonly Object lockerForThreads; - private EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); + private EventWaitHandle waitHandle; /// /// Constructor for creating n number of threads for tasks /// public MyThreadPool(int sizeThreads) { + waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); lockerForThreads = new(); if (sizeThreads <= 0) { @@ -85,19 +86,19 @@ private class MyThread private volatile Queue tasks; private Object locker; private CancellationToken token; - private EventWaitHandle? waitHandle; + private EventWaitHandle waitHandle; /// /// Task-based custom thread constructor /// - public MyThread(Queue tasks, CancellationToken token, object locker, EventWaitHandle? waitHandle) + public MyThread(Queue tasks, CancellationToken token, object locker, EventWaitHandle waitHandle) { + this.waitHandle = waitHandle; this.tasks = tasks; this.token = token; this.locker = locker; thread = new Thread(EternalCycle); thread.Start(); - this.waitHandle = waitHandle; } /// @@ -105,10 +106,6 @@ public MyThread(Queue tasks, CancellationToken token, object locker, Eve /// private void EternalCycle() { - if (waitHandle == null) - { - throw new NullReferenceException(); - } Action? task = null; while (!token.IsCancellationRequested) { diff --git a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs index 03d7051..5f672bf 100644 --- a/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs +++ b/MyThreadPool/TestsForMyThreadPool/TestsForMyThreadPool.cs @@ -13,7 +13,6 @@ public void ATestWithOneTaskForTenThreads() myThreadPool.Shutdown(); } - /* [Test] public void ATestWithTwoTasksForTenThreads() { @@ -24,7 +23,6 @@ public void ATestWithTwoTasksForTenThreads() Assert.That(secondTask.Result, Is.EqualTo(6)); myThreadPool.Shutdown(); } - */ [Test] public void WhenThereAreFewerThreadsThanTasks() @@ -55,7 +53,6 @@ public void IsContinueWithWorkingCorrectlyWithWithSeveralSubtask() myThreadPool.Shutdown(); } - /* [Test] public void NumberThreadsTheRequiredNumberIsCreated() { @@ -100,5 +97,4 @@ public void AnotherTasksWillNotBeAcceptedAndTheOldOnesWillBeFinalized() Assert.That(firstTask.Result, Is.EqualTo(4)); Assert.Throws(() => { var secondTask = myThreadPool.Submit(() => 3 + 3); }); } - */ } \ No newline at end of file From 5c81b3081154ee6fde9eb4f1a8ac440a8bba84c8 Mon Sep 17 00:00:00 2001 From: Artem Date: Wed, 27 Dec 2023 14:35:19 +0300 Subject: [PATCH 17/17] =?UTF-8?q?=D0=A7=D0=B0=D1=81=D1=82=D1=8C=20=D1=80?= =?UTF-8?q?=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MyThreadPool/MyThreadPool/MyThreadPool.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/MyThreadPool/MyThreadPool/MyThreadPool.cs b/MyThreadPool/MyThreadPool/MyThreadPool.cs index ada682e..857de17 100644 --- a/MyThreadPool/MyThreadPool/MyThreadPool.cs +++ b/MyThreadPool/MyThreadPool/MyThreadPool.cs @@ -132,10 +132,6 @@ private void EternalCycle() task(); } task = null; - if (token.IsCancellationRequested) - { - return; - } } } } @@ -160,7 +156,7 @@ private class MyTask : IMyTask private TResult? result; private Exception? exception; private CancellationTokenSource token; - private EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); + private ManualResetEvent resetEvent = new ManualResetEvent(false); private MyThreadPool? pool; /// @@ -171,12 +167,13 @@ public MyTask(Func supplier, CancellationTokenSource token, MyThreadPoo this.supplier = supplier; this.token = token; this.pool = pool; + this.result = default; } /// /// Get Result /// - public TResult? Result + public TResult Result { get { @@ -189,7 +186,7 @@ public TResult? Result { throw new AggregateException(exception); } - return result; + return result!; } }