From 81b20c7b5bb72ebc738d307943a8f58f170a2707 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Sun, 10 Oct 2021 16:57:10 +0300 Subject: [PATCH 01/15] base files --- ThreadPool/ThreadPool.sln | 16 ++++++++++++++ ThreadPool/ThreadPool/IMyTask.cs | 29 +++++++++++++++++++++++++ ThreadPool/ThreadPool/MyThreadPool.cs | 25 +++++++++++++++++++++ ThreadPool/ThreadPool/Program.cs | 12 ++++++++++ ThreadPool/ThreadPool/ThreadPool.csproj | 9 ++++++++ 5 files changed, 91 insertions(+) create mode 100644 ThreadPool/ThreadPool.sln create mode 100644 ThreadPool/ThreadPool/IMyTask.cs create mode 100644 ThreadPool/ThreadPool/MyThreadPool.cs create mode 100644 ThreadPool/ThreadPool/Program.cs create mode 100644 ThreadPool/ThreadPool/ThreadPool.csproj diff --git a/ThreadPool/ThreadPool.sln b/ThreadPool/ThreadPool.sln new file mode 100644 index 0000000..1e82724 --- /dev/null +++ b/ThreadPool/ThreadPool.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThreadPool", "ThreadPool\ThreadPool.csproj", "{E0D93E78-090C-4C9B-B545-DBB1534BC37D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/ThreadPool/ThreadPool/IMyTask.cs b/ThreadPool/ThreadPool/IMyTask.cs new file mode 100644 index 0000000..ead3512 --- /dev/null +++ b/ThreadPool/ThreadPool/IMyTask.cs @@ -0,0 +1,29 @@ +using System; + +namespace ThreadPool +{ + /// + /// + /// + /// + public interface IMyTask + { + /// + /// + /// + public bool IsCompleted { get; set; } + + /// + /// + /// + public TResult Result { get; set; } + + /// + /// + /// + /// + /// + /// + public IMyTask ContinueWith(Func func); + } +} \ No newline at end of file diff --git a/ThreadPool/ThreadPool/MyThreadPool.cs b/ThreadPool/ThreadPool/MyThreadPool.cs new file mode 100644 index 0000000..ee0a473 --- /dev/null +++ b/ThreadPool/ThreadPool/MyThreadPool.cs @@ -0,0 +1,25 @@ +using System; +using System.Threading; + +namespace ThreadPool +{ + public class MyThreadPool + { + private Thread[] _threads; + + MyThreadPool(int countThreads) + { + if (countThreads < 1) + { + throw new ArgumentException(); + } + + _threads = new Thread[countThreads]; + } + + public void Shutdown() + { + + } + } +} \ No newline at end of file diff --git a/ThreadPool/ThreadPool/Program.cs b/ThreadPool/ThreadPool/Program.cs new file mode 100644 index 0000000..5058794 --- /dev/null +++ b/ThreadPool/ThreadPool/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace ThreadPool +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} \ No newline at end of file diff --git a/ThreadPool/ThreadPool/ThreadPool.csproj b/ThreadPool/ThreadPool/ThreadPool.csproj new file mode 100644 index 0000000..a184b89 --- /dev/null +++ b/ThreadPool/ThreadPool/ThreadPool.csproj @@ -0,0 +1,9 @@ + + + + Exe + net5.0 + Windows + + + From 989fa255a23dbc6802307d2323a114579c85e2c1 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Wed, 20 Oct 2021 21:31:02 +0300 Subject: [PATCH 02/15] add test --- ThreadPool/ThreadPool.sln | 6 + ThreadPool/ThreadPool/IMyTask.cs | 22 ++-- ThreadPool/ThreadPool/MyTask.cs | 74 ++++++++++++ ThreadPool/ThreadPool/MyThreadPool.cs | 68 ++++++++++- ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 108 ++++++++++++++++++ .../ThreadPoolTest/ThreadPoolTest.csproj | 20 ++++ 6 files changed, 281 insertions(+), 17 deletions(-) create mode 100644 ThreadPool/ThreadPool/MyTask.cs create mode 100644 ThreadPool/ThreadPoolTest/ThreadPoolTest.cs create mode 100644 ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj diff --git a/ThreadPool/ThreadPool.sln b/ThreadPool/ThreadPool.sln index 1e82724..9bef84d 100644 --- a/ThreadPool/ThreadPool.sln +++ b/ThreadPool/ThreadPool.sln @@ -2,6 +2,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThreadPool", "ThreadPool\ThreadPool.csproj", "{E0D93E78-090C-4C9B-B545-DBB1534BC37D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThreadPoolTest", "ThreadPoolTest\ThreadPoolTest.csproj", "{AE21AEB8-EC3E-4D26-A154-E8C11BA4F93E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -12,5 +14,9 @@ Global {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Debug|Any CPU.Build.0 = Debug|Any CPU {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Release|Any CPU.Build.0 = Release|Any CPU + {AE21AEB8-EC3E-4D26-A154-E8C11BA4F93E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE21AEB8-EC3E-4D26-A154-E8C11BA4F93E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE21AEB8-EC3E-4D26-A154-E8C11BA4F93E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE21AEB8-EC3E-4D26-A154-E8C11BA4F93E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/ThreadPool/ThreadPool/IMyTask.cs b/ThreadPool/ThreadPool/IMyTask.cs index ead3512..72cbfdc 100644 --- a/ThreadPool/ThreadPool/IMyTask.cs +++ b/ThreadPool/ThreadPool/IMyTask.cs @@ -3,27 +3,23 @@ namespace ThreadPool { /// - /// + /// task interface /// - /// - public interface IMyTask + public interface IMyTask { /// - /// + /// shows whether the task is completed or not /// public bool IsCompleted { get; set; } - + /// - /// + /// returns the result of the task /// - public TResult Result { get; set; } + public TResult Result { get; } - /// - /// + /*/// + /// /// - /// - /// - /// - public IMyTask ContinueWith(Func func); + public IMyTask ContinueWith(Func func)*/ } } \ No newline at end of file diff --git a/ThreadPool/ThreadPool/MyTask.cs b/ThreadPool/ThreadPool/MyTask.cs new file mode 100644 index 0000000..a376bdc --- /dev/null +++ b/ThreadPool/ThreadPool/MyTask.cs @@ -0,0 +1,74 @@ +using System; +using System.Threading; + +namespace ThreadPool +{ + /// + /// task classs + /// + public class MyTask : IMyTask + { + private Func _func; + private TResult _result; + private Exception _resultException = null; + private readonly object _locker = new(); + private readonly ManualResetEvent _waiterManual = new(false); + + /// + /// shows whether the task is completed or not + /// + public bool IsCompleted { get; set; } + + /// + /// returns the result of the task + /// + public TResult Result + { + get + { + _waiterManual.WaitOne(); + if (_resultException != null) + { + throw new AggregateException(_resultException); + } + + return _result; + } + } + + /// + /// constructor + /// + public MyTask(Func function) + { + _func = function ?? throw new ArgumentException(); + } + + /// + /// counting result of task + /// + public void Count() + { + try + { + _result = _func(); + } + catch (Exception funcException) + { + _resultException = funcException; + } + + lock (_locker) + { + _func = null; + IsCompleted = true; + _waiterManual.Set(); + } + } + + /*/// + /// + /// + public IMyTask ContinueWith(Func func)*/ + } +} \ No newline at end of file diff --git a/ThreadPool/ThreadPool/MyThreadPool.cs b/ThreadPool/ThreadPool/MyThreadPool.cs index ee0a473..ca8bec6 100644 --- a/ThreadPool/ThreadPool/MyThreadPool.cs +++ b/ThreadPool/ThreadPool/MyThreadPool.cs @@ -1,13 +1,23 @@ using System; +using System.Collections.Concurrent; +using System.Linq; using System.Threading; namespace ThreadPool { public class MyThreadPool { - private Thread[] _threads; - - MyThreadPool(int countThreads) + private readonly Thread[] _threads; + private readonly CancellationTokenSource _token = new(); + private readonly ConcurrentQueue _tasksQueue = new(); + private readonly AutoResetEvent _waiterNewTask = new AutoResetEvent(false); + private readonly AutoResetEvent _waiterTaskDone = new AutoResetEvent(false); + private readonly object _lockObject = new(); + + /// + /// constructor + /// + public MyThreadPool(int countThreads) { if (countThreads < 1) { @@ -15,11 +25,61 @@ public class MyThreadPool } _threads = new Thread[countThreads]; + for (int i = 0; i < countThreads; i++) + { + _threads[i] = new Thread(() => + { + while (!_token.IsCancellationRequested || !_tasksQueue.IsEmpty) + { + if (_tasksQueue.TryDequeue(out Action action)) + { + action(); + } + else + { + _waiterNewTask.WaitOne(); + if (!_tasksQueue.IsEmpty) + { + _waiterNewTask.Set(); + } + } + } + + _waiterTaskDone.Set(); + }); + + _threads[i].Start(); + } } + /// + /// add task + /// + public IMyTask AddTask(Func function) + { + lock (_lockObject) + { + if (_token.IsCancellationRequested) + { + throw new InvalidOperationException(); + } + } + + var task = new MyTask(function); + _tasksQueue.Enqueue(task.Count); + _waiterNewTask.Set(); + return task; + } + + /// + /// close threads + /// public void Shutdown() { - + lock (_lockObject) + { + _token.Cancel(); + } } } } \ No newline at end of file diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs new file mode 100644 index 0000000..6541191 --- /dev/null +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -0,0 +1,108 @@ +using System; +using System.Threading; +using NUnit.Framework; +using ThreadPool; + +namespace ThreadPoolTest +{ + public class Tests + { + private ThreadPool.MyThreadPool _threadPool; + private readonly int _numberOfThreads = Environment.ProcessorCount; + + [SetUp] + public void Setup() + { + _threadPool = new(Environment.ProcessorCount); + } + + [Test] + public void CountingThreadsTest1() + { + int number = 0; + for (int i = 0; i < 20; i++) + { + _threadPool.AddTask(() => + { + Interlocked.Increment(ref number); + Thread.Sleep(3000); + return "qwe"; + }); + } + + Thread.Sleep(300); + Assert.AreEqual(_numberOfThreads, number); + } + + + [Test] + public void CountingThreadsTest2() + { + int number = 0; + _threadPool.AddTask(() => + { + Interlocked.Increment(ref number); + Thread.Sleep(3000); + return "qwe"; + }); + + Thread.Sleep(300); + Assert.AreEqual(1, number); + } + + [Test] + public void ShutdownTest() + { + int number = 0; + for (int i = 0; i < 20; i++) + { + _threadPool.AddTask(() => + { + Interlocked.Increment(ref number); + Thread.Sleep(1000); + return "qwe"; + }); + } + + Thread.Sleep(100); + _threadPool.Shutdown(); + + Thread.Sleep(500); + Assert.AreEqual(_numberOfThreads, number); + } + + [Test] + public void TaskResultTest() + { + int number1 = 2; + int number2 = 2; + var task1 = _threadPool.AddTask(() => + { + number1 += 2; + return number1; + }); + var task2 = _threadPool.AddTask(() => + { + number2 *= 5; + return number2; + }); + + Thread.Sleep(300); + Assert.AreEqual(4, task1.Result); + Assert.AreEqual(10, task2.Result); + } + + [Test] + public void ExceptionInThreadPoolConstructorTest() + { + Assert.Throws(() => new MyThreadPool(0)); + } + + [Test] + public void ExceptionAfterShutdownTest() + { + _threadPool.Shutdown(); + Assert.Throws(() => _threadPool.AddTask(() => 5)); + } + } +} \ No newline at end of file diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj b/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj new file mode 100644 index 0000000..eed9725 --- /dev/null +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj @@ -0,0 +1,20 @@ + + + + net5.0 + + false + + + + + + + + + + + + + + From 80dba3bb6c13f956ee2f8a361a525287b0e6dbdd Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 22 Nov 2021 19:44:49 +0300 Subject: [PATCH 03/15] fix code --- ThreadPool/ThreadPool/IMyTask.cs | 8 +- ThreadPool/ThreadPool/MyTask.cs | 74 ----------- ThreadPool/ThreadPool/MyThreadPool.cs | 134 +++++++++++++++++++- ThreadPool/ThreadPool/Program.cs | 12 -- ThreadPool/ThreadPool/ThreadPool.csproj | 1 - ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 96 ++++++-------- 6 files changed, 175 insertions(+), 150 deletions(-) delete mode 100644 ThreadPool/ThreadPool/MyTask.cs delete mode 100644 ThreadPool/ThreadPool/Program.cs diff --git a/ThreadPool/ThreadPool/IMyTask.cs b/ThreadPool/ThreadPool/IMyTask.cs index 72cbfdc..97b7005 100644 --- a/ThreadPool/ThreadPool/IMyTask.cs +++ b/ThreadPool/ThreadPool/IMyTask.cs @@ -3,7 +3,7 @@ namespace ThreadPool { /// - /// task interface + /// interface for object from MyThreadPool /// public interface IMyTask { @@ -17,9 +17,9 @@ public interface IMyTask /// public TResult Result { get; } - /*/// - /// + /// + /// continues calculating /// - public IMyTask ContinueWith(Func func)*/ + public IMyTask ContinueWith(Func func); } } \ No newline at end of file diff --git a/ThreadPool/ThreadPool/MyTask.cs b/ThreadPool/ThreadPool/MyTask.cs deleted file mode 100644 index a376bdc..0000000 --- a/ThreadPool/ThreadPool/MyTask.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Threading; - -namespace ThreadPool -{ - /// - /// task classs - /// - public class MyTask : IMyTask - { - private Func _func; - private TResult _result; - private Exception _resultException = null; - private readonly object _locker = new(); - private readonly ManualResetEvent _waiterManual = new(false); - - /// - /// shows whether the task is completed or not - /// - public bool IsCompleted { get; set; } - - /// - /// returns the result of the task - /// - public TResult Result - { - get - { - _waiterManual.WaitOne(); - if (_resultException != null) - { - throw new AggregateException(_resultException); - } - - return _result; - } - } - - /// - /// constructor - /// - public MyTask(Func function) - { - _func = function ?? throw new ArgumentException(); - } - - /// - /// counting result of task - /// - public void Count() - { - try - { - _result = _func(); - } - catch (Exception funcException) - { - _resultException = funcException; - } - - lock (_locker) - { - _func = null; - IsCompleted = true; - _waiterManual.Set(); - } - } - - /*/// - /// - /// - public IMyTask ContinueWith(Func func)*/ - } -} \ No newline at end of file diff --git a/ThreadPool/ThreadPool/MyThreadPool.cs b/ThreadPool/ThreadPool/MyThreadPool.cs index ca8bec6..8851d29 100644 --- a/ThreadPool/ThreadPool/MyThreadPool.cs +++ b/ThreadPool/ThreadPool/MyThreadPool.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Threading; +using System.Threading.Tasks; namespace ThreadPool { @@ -12,6 +14,7 @@ public class MyThreadPool private readonly ConcurrentQueue _tasksQueue = new(); private readonly AutoResetEvent _waiterNewTask = new AutoResetEvent(false); private readonly AutoResetEvent _waiterTaskDone = new AutoResetEvent(false); + private int _freeThreadsCount = 0; private readonly object _lockObject = new(); /// @@ -21,7 +24,7 @@ public MyThreadPool(int countThreads) { if (countThreads < 1) { - throw new ArgumentException(); + throw new ArgumentOutOfRangeException(nameof(countThreads)); } _threads = new Thread[countThreads]; @@ -45,6 +48,7 @@ public MyThreadPool(int countThreads) } } + Interlocked.Increment(ref _freeThreadsCount); _waiterTaskDone.Set(); }); @@ -65,9 +69,13 @@ public IMyTask AddTask(Func function) } } - var task = new MyTask(function); - _tasksQueue.Enqueue(task.Count); - _waiterNewTask.Set(); + var task = new MyTask(function, this); + lock (_lockObject) + { + _tasksQueue.Enqueue(task.Count); + _waiterNewTask.Set(); + } + return task; } @@ -80,6 +88,124 @@ public void Shutdown() { _token.Cancel(); } + + while (_freeThreadsCount != _threads.Length) + { + _waiterNewTask.Set(); + _waiterTaskDone.WaitOne(); + _waiterTaskDone.Reset(); + } + } + + /// + /// class for parallel tasks + /// + private class MyTask : IMyTask + { + private Func _func; + private TResult _result; + private Exception _resultException = null; + private readonly object _locker = new(); + private readonly ManualResetEvent _waiterManual = new(false); + private Queue _continueWithTasksQueue = new(); + private readonly MyThreadPool _myThreadPool; + + /// + /// shows whether the task is completed or not + /// + public bool IsCompleted { get; set; } + + /// + /// returns the result of the task + /// + public TResult Result + { + get + { + _waiterManual.WaitOne(); + if (_resultException != null) + { + throw new AggregateException(_resultException); + } + + return _result; + } + } + + /// + /// constructor + /// + public MyTask(Func function, MyThreadPool myThreadPool) + { + _func = function ?? throw new ArgumentNullException(nameof(function)); + _myThreadPool = myThreadPool; + } + + /// + /// counting result of task + /// + public void Count() + { + try + { + _result = _func(); + } + catch (Exception funcException) + { + _resultException = funcException; + } + + lock (_locker) + { + _func = null; + IsCompleted = true; + _waiterManual.Set(); + } + + lock (_locker) + { + while (_continueWithTasksQueue.Count > 0) + { + var action = _continueWithTasksQueue.Dequeue(); + lock (_locker) + { + _myThreadPool._tasksQueue.Enqueue(action); + _waiterManual.Set(); + } + } + } + } + + /// + /// continues calculating + /// + public IMyTask ContinueWith(Func func) + { + lock (_locker) + { + if (_myThreadPool._token.IsCancellationRequested) + { + throw new InvalidOperationException(); + } + + var task = new MyTask(() => func(Result), _myThreadPool); + _continueWithTasksQueue.Enqueue(task.Count); + if (IsCompleted) + { + while (_continueWithTasksQueue.Count > 0) + { + var action = _continueWithTasksQueue.Dequeue(); + lock (_locker) + { + _myThreadPool._tasksQueue.Enqueue(action); + _waiterManual.Set(); + } + } + } + + return task; + } + } } } } \ No newline at end of file diff --git a/ThreadPool/ThreadPool/Program.cs b/ThreadPool/ThreadPool/Program.cs deleted file mode 100644 index 5058794..0000000 --- a/ThreadPool/ThreadPool/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace ThreadPool -{ - class Program - { - static void Main(string[] args) - { - Console.WriteLine("Hello World!"); - } - } -} \ No newline at end of file diff --git a/ThreadPool/ThreadPool/ThreadPool.csproj b/ThreadPool/ThreadPool/ThreadPool.csproj index a184b89..3fb55c8 100644 --- a/ThreadPool/ThreadPool/ThreadPool.csproj +++ b/ThreadPool/ThreadPool/ThreadPool.csproj @@ -1,7 +1,6 @@ - Exe net5.0 Windows diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs index 6541191..7fd43f5 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Threading; using NUnit.Framework; using ThreadPool; @@ -7,68 +8,55 @@ namespace ThreadPoolTest { public class Tests { - private ThreadPool.MyThreadPool _threadPool; - private readonly int _numberOfThreads = Environment.ProcessorCount; + private MyThreadPool _threadPool; + private readonly int _numberOfThreads = 4; [SetUp] public void Setup() - { - _threadPool = new(Environment.ProcessorCount); - } + => _threadPool = new(Environment.ProcessorCount); + + [TearDown] + public void TearDown() + => _threadPool.Shutdown(); + + [TearDown] + public void Teardown() + => _threadPool.Shutdown(); + + [Test] + public void NullFunctionShouldThrowException() + => Assert.Throws(() => _threadPool.AddTask(null)); + [Test] - public void CountingThreadsTest1() + public void ResultShouldThrowException() { - int number = 0; - for (int i = 0; i < 20; i++) - { - _threadPool.AddTask(() => - { - Interlocked.Increment(ref number); - Thread.Sleep(3000); - return "qwe"; - }); - } - - Thread.Sleep(300); - Assert.AreEqual(_numberOfThreads, number); + var task = _threadPool.AddTask(() => throw new ArgumentOutOfRangeException()); + Assert.Throws(() => Result(task)); } + + private object Result(IMyTask task) + => task.Result; + [Test] + public void ExceptionInThreadPoolConstructorTest() + => Assert.Throws(() => new MyThreadPool(0)); [Test] - public void CountingThreadsTest2() + public void ExceptionAfterShutdownTest() { - int number = 0; - _threadPool.AddTask(() => - { - Interlocked.Increment(ref number); - Thread.Sleep(3000); - return "qwe"; - }); - - Thread.Sleep(300); - Assert.AreEqual(1, number); + _threadPool.Shutdown(); + Assert.Throws(() => _threadPool.AddTask(() => 5)); } [Test] - public void ShutdownTest() + public void GetTaskAfterShutdown() { - int number = 0; - for (int i = 0; i < 20; i++) - { - _threadPool.AddTask(() => - { - Interlocked.Increment(ref number); - Thread.Sleep(1000); - return "qwe"; - }); - } - - Thread.Sleep(100); + var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); + var task2 = _threadPool.AddTask(() => _numberOfThreads * _numberOfThreads); _threadPool.Shutdown(); - - Thread.Sleep(500); - Assert.AreEqual(_numberOfThreads, number); + Assert.AreEqual(12, task1.Result); + Assert.AreEqual(16, task2.Result); } [Test] @@ -93,16 +81,14 @@ public void TaskResultTest() } [Test] - public void ExceptionInThreadPoolConstructorTest() + public void ContinueWithTest() { - Assert.Throws(() => new MyThreadPool(0)); - } - - [Test] - public void ExceptionAfterShutdownTest() - { - _threadPool.Shutdown(); - Assert.Throws(() => _threadPool.AddTask(() => 5)); + var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); //12 + var task2 = task1.ContinueWith(x => x + _numberOfThreads); //12 + 4 + var task3 = task1.ContinueWith(x => x + task2.Result); // 12 + 16 + Assert.AreEqual(12, task1.Result); + Assert.AreEqual(16, task2.Result); + Assert.AreEqual(28, task3.Result); } } } \ No newline at end of file From 654b4aa1e051af7eef9d1c7d1451b5c204829878 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 22 Nov 2021 21:39:55 +0300 Subject: [PATCH 04/15] fix --- ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 29 +++++---------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs index 7fd43f5..b450085 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -14,27 +14,22 @@ public class Tests [SetUp] public void Setup() => _threadPool = new(Environment.ProcessorCount); - [TearDown] public void TearDown() => _threadPool.Shutdown(); - - [TearDown] - public void Teardown() - => _threadPool.Shutdown(); [Test] public void NullFunctionShouldThrowException() => Assert.Throws(() => _threadPool.AddTask(null)); - + [Test] public void ResultShouldThrowException() { var task = _threadPool.AddTask(() => throw new ArgumentOutOfRangeException()); Assert.Throws(() => Result(task)); } - + private object Result(IMyTask task) => task.Result; @@ -64,18 +59,8 @@ public void TaskResultTest() { int number1 = 2; int number2 = 2; - var task1 = _threadPool.AddTask(() => - { - number1 += 2; - return number1; - }); - var task2 = _threadPool.AddTask(() => - { - number2 *= 5; - return number2; - }); - - Thread.Sleep(300); + var task1 = _threadPool.AddTask(() => number1 + 2); + var task2 = _threadPool.AddTask(() => number2 * 5); Assert.AreEqual(4, task1.Result); Assert.AreEqual(10, task2.Result); } @@ -83,9 +68,9 @@ public void TaskResultTest() [Test] public void ContinueWithTest() { - var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); //12 - var task2 = task1.ContinueWith(x => x + _numberOfThreads); //12 + 4 - var task3 = task1.ContinueWith(x => x + task2.Result); // 12 + 16 + var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); //12 + var task2 = task1.ContinueWith(x => x + _numberOfThreads); //12 + 4 + var task3 = task1.ContinueWith(x => x + task2.Result); // 12 + 16 Assert.AreEqual(12, task1.Result); Assert.AreEqual(16, task2.Result); Assert.AreEqual(28, task3.Result); From c1122bf52c4a51622339dcc8cce62bae075f28e3 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Sun, 28 Nov 2021 12:21:41 +0300 Subject: [PATCH 05/15] fix test --- ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs index b450085..7e0a8e7 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -1,6 +1,4 @@ using System; -using System.Diagnostics; -using System.Threading; using NUnit.Framework; using ThreadPool; @@ -15,19 +13,23 @@ public class Tests public void Setup() => _threadPool = new(Environment.ProcessorCount); - [TearDown] + /*[TearDown] public void TearDown() - => _threadPool.Shutdown(); + => _threadPool.Shutdown();*/ [Test] public void NullFunctionShouldThrowException() - => Assert.Throws(() => _threadPool.AddTask(null)); + { + Assert.Throws(() => _threadPool.AddTask(null)); + _threadPool.Shutdown(); + } [Test] public void ResultShouldThrowException() { var task = _threadPool.AddTask(() => throw new ArgumentOutOfRangeException()); Assert.Throws(() => Result(task)); + _threadPool.Shutdown(); } private object Result(IMyTask task) @@ -35,7 +37,10 @@ private object Result(IMyTask task) [Test] public void ExceptionInThreadPoolConstructorTest() - => Assert.Throws(() => new MyThreadPool(0)); + { + Assert.Throws(() => new MyThreadPool(0)); + _threadPool.Shutdown(); + } [Test] public void ExceptionAfterShutdownTest() @@ -61,6 +66,7 @@ public void TaskResultTest() int number2 = 2; var task1 = _threadPool.AddTask(() => number1 + 2); var task2 = _threadPool.AddTask(() => number2 * 5); + _threadPool.Shutdown(); Assert.AreEqual(4, task1.Result); Assert.AreEqual(10, task2.Result); } @@ -71,6 +77,7 @@ public void ContinueWithTest() var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); //12 var task2 = task1.ContinueWith(x => x + _numberOfThreads); //12 + 4 var task3 = task1.ContinueWith(x => x + task2.Result); // 12 + 16 + _threadPool.Shutdown(); Assert.AreEqual(12, task1.Result); Assert.AreEqual(16, task2.Result); Assert.AreEqual(28, task3.Result); From f580fa2665522d55fc39a9adbeec701ce3134f11 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Sun, 28 Nov 2021 12:23:39 +0300 Subject: [PATCH 06/15] delete commenting string --- ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs index 7e0a8e7..337c545 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -13,10 +13,6 @@ public class Tests public void Setup() => _threadPool = new(Environment.ProcessorCount); - /*[TearDown] - public void TearDown() - => _threadPool.Shutdown();*/ - [Test] public void NullFunctionShouldThrowException() { From 7c3d283294263a6e38a00b1029ca22b149c7f19b Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Tue, 7 Dec 2021 00:08:22 +0300 Subject: [PATCH 07/15] fix code --- ThreadPool/ThreadPool/MyThreadPool.cs | 24 +++++++-------------- ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 10 ++++----- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/ThreadPool/ThreadPool/MyThreadPool.cs b/ThreadPool/ThreadPool/MyThreadPool.cs index 8851d29..b6065be 100644 --- a/ThreadPool/ThreadPool/MyThreadPool.cs +++ b/ThreadPool/ThreadPool/MyThreadPool.cs @@ -61,22 +61,17 @@ public MyThreadPool(int countThreads) /// public IMyTask AddTask(Func function) { - lock (_lockObject) + if (_token.IsCancellationRequested) { - if (_token.IsCancellationRequested) - { - throw new InvalidOperationException(); - } + throw new InvalidOperationException(); } - - var task = new MyTask(function, this); lock (_lockObject) { + var task = new MyTask(function, this); _tasksQueue.Enqueue(task.Count); _waiterNewTask.Set(); + return task; } - - return task; } /// @@ -167,10 +162,10 @@ public void Count() while (_continueWithTasksQueue.Count > 0) { var action = _continueWithTasksQueue.Dequeue(); - lock (_locker) + lock (_myThreadPool._lockObject) { _myThreadPool._tasksQueue.Enqueue(action); - _waiterManual.Set(); + _myThreadPool._waiterNewTask.Set(); } } } @@ -195,11 +190,8 @@ public IMyTask ContinueWith(Func fu while (_continueWithTasksQueue.Count > 0) { var action = _continueWithTasksQueue.Dequeue(); - lock (_locker) - { - _myThreadPool._tasksQueue.Enqueue(action); - _waiterManual.Set(); - } + _myThreadPool._tasksQueue.Enqueue(action); + _waiterManual.Set(); } } diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs index 337c545..f74b10b 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -13,11 +13,14 @@ public class Tests public void Setup() => _threadPool = new(Environment.ProcessorCount); + [TearDown] + public void TearDown() + => _threadPool.Shutdown(); + [Test] public void NullFunctionShouldThrowException() { Assert.Throws(() => _threadPool.AddTask(null)); - _threadPool.Shutdown(); } [Test] @@ -25,7 +28,6 @@ public void ResultShouldThrowException() { var task = _threadPool.AddTask(() => throw new ArgumentOutOfRangeException()); Assert.Throws(() => Result(task)); - _threadPool.Shutdown(); } private object Result(IMyTask task) @@ -35,7 +37,6 @@ private object Result(IMyTask task) public void ExceptionInThreadPoolConstructorTest() { Assert.Throws(() => new MyThreadPool(0)); - _threadPool.Shutdown(); } [Test] @@ -50,7 +51,6 @@ public void GetTaskAfterShutdown() { var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); var task2 = _threadPool.AddTask(() => _numberOfThreads * _numberOfThreads); - _threadPool.Shutdown(); Assert.AreEqual(12, task1.Result); Assert.AreEqual(16, task2.Result); } @@ -62,7 +62,6 @@ public void TaskResultTest() int number2 = 2; var task1 = _threadPool.AddTask(() => number1 + 2); var task2 = _threadPool.AddTask(() => number2 * 5); - _threadPool.Shutdown(); Assert.AreEqual(4, task1.Result); Assert.AreEqual(10, task2.Result); } @@ -73,7 +72,6 @@ public void ContinueWithTest() var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); //12 var task2 = task1.ContinueWith(x => x + _numberOfThreads); //12 + 4 var task3 = task1.ContinueWith(x => x + task2.Result); // 12 + 16 - _threadPool.Shutdown(); Assert.AreEqual(12, task1.Result); Assert.AreEqual(16, task2.Result); Assert.AreEqual(28, task3.Result); From f6e20908cb858ae8db8e2b5d727ba525e6587ea9 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Tue, 7 Dec 2021 21:27:22 +0300 Subject: [PATCH 08/15] fix deadlock --- ThreadPool/ThreadPool/MyThreadPool.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/ThreadPool/ThreadPool/MyThreadPool.cs b/ThreadPool/ThreadPool/MyThreadPool.cs index b6065be..fbdb8ae 100644 --- a/ThreadPool/ThreadPool/MyThreadPool.cs +++ b/ThreadPool/ThreadPool/MyThreadPool.cs @@ -176,27 +176,30 @@ public void Count() /// public IMyTask ContinueWith(Func func) { - lock (_locker) + lock (_myThreadPool._lockObject) { if (_myThreadPool._token.IsCancellationRequested) { throw new InvalidOperationException(); } - - var task = new MyTask(() => func(Result), _myThreadPool); - _continueWithTasksQueue.Enqueue(task.Count); - if (IsCompleted) + } + + var task = new MyTask(() => func(Result), _myThreadPool); + _continueWithTasksQueue.Enqueue(task.Count); + if (IsCompleted) + { + while (_continueWithTasksQueue.Count > 0) { - while (_continueWithTasksQueue.Count > 0) + lock (_myThreadPool._lockObject) { var action = _continueWithTasksQueue.Dequeue(); _myThreadPool._tasksQueue.Enqueue(action); - _waiterManual.Set(); + _myThreadPool._waiterNewTask.Set(); } - } - return task; + } } + return task; } } } From b48bb230be09f680d6bc216a03915b089240cd1b Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Wed, 22 Dec 2021 17:04:33 +0300 Subject: [PATCH 09/15] fix --- ThreadPool/ThreadPool/MyThreadPool.cs | 49 +++++++++-------- ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 59 +++++++++++++++++++++ 2 files changed, 86 insertions(+), 22 deletions(-) diff --git a/ThreadPool/ThreadPool/MyThreadPool.cs b/ThreadPool/ThreadPool/MyThreadPool.cs index fbdb8ae..f800c6f 100644 --- a/ThreadPool/ThreadPool/MyThreadPool.cs +++ b/ThreadPool/ThreadPool/MyThreadPool.cs @@ -61,19 +61,33 @@ public MyThreadPool(int countThreads) /// public IMyTask AddTask(Func function) { - if (_token.IsCancellationRequested) - { - throw new InvalidOperationException(); - } + ReadyToAddNewTask(); lock (_lockObject) { + if (_token.IsCancellationRequested) + { + throw new InvalidOperationException(); + } var task = new MyTask(function, this); - _tasksQueue.Enqueue(task.Count); - _waiterNewTask.Set(); + AddInTaskQueue(task.Count); return task; } } + private void ReadyToAddNewTask() + { + if (_token.IsCancellationRequested) + { + throw new InvalidOperationException(); + } + } + + private void AddInTaskQueue(Action task) + { + _tasksQueue.Enqueue(task); + _waiterNewTask.Set(); + } + /// /// close threads /// @@ -164,8 +178,7 @@ public void Count() var action = _continueWithTasksQueue.Dequeue(); lock (_myThreadPool._lockObject) { - _myThreadPool._tasksQueue.Enqueue(action); - _myThreadPool._waiterNewTask.Set(); + _myThreadPool.AddInTaskQueue(action); } } } @@ -178,28 +191,20 @@ public IMyTask ContinueWith(Func fu { lock (_myThreadPool._lockObject) { - if (_myThreadPool._token.IsCancellationRequested) + _myThreadPool.ReadyToAddNewTask(); + var task = new MyTask(() => func(Result), _myThreadPool); + _continueWithTasksQueue.Enqueue(task.Count); + if (IsCompleted) { - throw new InvalidOperationException(); - } - } - - var task = new MyTask(() => func(Result), _myThreadPool); - _continueWithTasksQueue.Enqueue(task.Count); - if (IsCompleted) - { - while (_continueWithTasksQueue.Count > 0) - { - lock (_myThreadPool._lockObject) + while (_continueWithTasksQueue.Count > 0) { var action = _continueWithTasksQueue.Dequeue(); _myThreadPool._tasksQueue.Enqueue(action); _myThreadPool._waiterNewTask.Set(); } - } + return task; } - return task; } } } diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs index f74b10b..9b93c4d 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -30,6 +30,65 @@ public void ResultShouldThrowException() Assert.Throws(() => Result(task)); } + [Test] + public void ParallelAddTaskTest() + { + var tasks = new IMyTask[30]; + var functions = new Func[30]; + for (int i = 0; i < 30; i++) + { + var index = i; + functions[i] = () => + { + var result = 0; + for (int j = 0; j < 100; j++) + { + result++; + } + return result + index; + }; + } + + for (int i = 0; i < 30; i++) + { + tasks[i] = _threadPool.AddTask(functions[i]); + } + for (int i = 0; i < 30; i++) + { + Assert.AreEqual(100 + i, tasks[i].Result); + } + } + + [Test] + public void ShutdownWhileTaskCountTest() + { + var tasks = new IMyTask[30]; + var functions = new Func[30]; + for (int i = 0; i < 30; i++) + { + var i1 = i; + functions[i] = () => + { + var result = 0; + for (int j = 0; j < 10; j++) + { + result += 10; + } + return result + i1; + }; + } + + for (int i = 0; i < 30; i++) + { + tasks[i] = _threadPool.AddTask(functions[i]); + } + _threadPool.Shutdown(); + for (int i = 0; i < 30; i++) + { + Assert.AreEqual(100 + i, tasks[i].Result); + } + } + private object Result(IMyTask task) => task.Result; From 8e500714f9bd0540f1f7b63dccde86f1afbdf133 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 14 Feb 2022 11:29:03 +0300 Subject: [PATCH 10/15] change --- ThreadPool/ThreadPool/MyThreadPool.cs | 3 +++ ThreadPool/ThreadPool/ThreadPool.csproj | 2 +- ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ThreadPool/ThreadPool/MyThreadPool.cs b/ThreadPool/ThreadPool/MyThreadPool.cs index f800c6f..819bbca 100644 --- a/ThreadPool/ThreadPool/MyThreadPool.cs +++ b/ThreadPool/ThreadPool/MyThreadPool.cs @@ -7,6 +7,9 @@ namespace ThreadPool { + /// + /// pool of threads that can be used to execute tasks + /// public class MyThreadPool { private readonly Thread[] _threads; diff --git a/ThreadPool/ThreadPool/ThreadPool.csproj b/ThreadPool/ThreadPool/ThreadPool.csproj index 3fb55c8..1542bbf 100644 --- a/ThreadPool/ThreadPool/ThreadPool.csproj +++ b/ThreadPool/ThreadPool/ThreadPool.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 Windows diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj b/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj index eed9725..a82263a 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj @@ -1,7 +1,7 @@ - net5.0 + net6.0 false From 0dce30f9b65b05eb2c806ac5701fac1c0c700e63 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 14 Feb 2022 13:36:14 +0300 Subject: [PATCH 11/15] update appveyor.yml --- appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 9809100..d79f319 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,3 +1,6 @@ +image: Visual Studio 2022 + + build_script: - For /R %%I in (*.sln) do dotnet test %%I test: of \ No newline at end of file From a692a03911643701cabe7e995ae4879b02fde3d3 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Wed, 9 Mar 2022 13:45:45 +0300 Subject: [PATCH 12/15] fix --- ThreadPool/ThreadPool/IMyTask.cs | 33 +-- ThreadPool/ThreadPool/MyThreadPool.cs | 288 ++++++++++---------- ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 1 - 3 files changed, 156 insertions(+), 166 deletions(-) diff --git a/ThreadPool/ThreadPool/IMyTask.cs b/ThreadPool/ThreadPool/IMyTask.cs index 97b7005..fd46cb0 100644 --- a/ThreadPool/ThreadPool/IMyTask.cs +++ b/ThreadPool/ThreadPool/IMyTask.cs @@ -1,25 +1,22 @@ using System; -namespace ThreadPool +/// +/// interface for object from MyThreadPool +/// +public interface IMyTask { /// - /// interface for object from MyThreadPool + /// shows whether the task is completed or not /// - public interface IMyTask - { - /// - /// shows whether the task is completed or not - /// - public bool IsCompleted { get; set; } + public bool IsCompleted { get; set; } - /// - /// returns the result of the task - /// - public TResult Result { get; } + /// + /// returns the result of the task + /// + public TResult Result { get; } - /// - /// continues calculating - /// - public IMyTask ContinueWith(Func func); - } -} \ No newline at end of file + /// + /// continues calculating + /// + public IMyTask ContinueWith(Func func); +} diff --git a/ThreadPool/ThreadPool/MyThreadPool.cs b/ThreadPool/ThreadPool/MyThreadPool.cs index 819bbca..0ae67c8 100644 --- a/ThreadPool/ThreadPool/MyThreadPool.cs +++ b/ThreadPool/ThreadPool/MyThreadPool.cs @@ -5,209 +5,203 @@ using System.Threading; using System.Threading.Tasks; -namespace ThreadPool +/// +/// pool of threads that can be used to execute tasks +/// +public class MyThreadPool { + private readonly Thread[] _threads; + private readonly CancellationTokenSource _token = new(); + private readonly ConcurrentQueue _tasksQueue = new(); + private readonly AutoResetEvent _waiterNewTask = new AutoResetEvent(false); + private readonly AutoResetEvent _waiterTaskDone = new AutoResetEvent(false); + private volatile int _freeThreadsCount = 0; + private readonly object _lockObject = new(); + /// - /// pool of threads that can be used to execute tasks + /// constructor /// - public class MyThreadPool + public MyThreadPool(int countThreads) { - private readonly Thread[] _threads; - private readonly CancellationTokenSource _token = new(); - private readonly ConcurrentQueue _tasksQueue = new(); - private readonly AutoResetEvent _waiterNewTask = new AutoResetEvent(false); - private readonly AutoResetEvent _waiterTaskDone = new AutoResetEvent(false); - private int _freeThreadsCount = 0; - private readonly object _lockObject = new(); - - /// - /// constructor - /// - public MyThreadPool(int countThreads) + if (countThreads < 1) { - if (countThreads < 1) - { - throw new ArgumentOutOfRangeException(nameof(countThreads)); - } + throw new ArgumentOutOfRangeException(nameof(countThreads)); + } - _threads = new Thread[countThreads]; - for (int i = 0; i < countThreads; i++) + _threads = new Thread[countThreads]; + for (int i = 0; i < countThreads; i++) + { + _threads[i] = new Thread(() => { - _threads[i] = new Thread(() => + while (!_token.IsCancellationRequested || !_tasksQueue.IsEmpty) { - while (!_token.IsCancellationRequested || !_tasksQueue.IsEmpty) + if (_tasksQueue.TryDequeue(out Action action)) { - if (_tasksQueue.TryDequeue(out Action action)) - { - action(); - } - else + action(); + } + else + { + _waiterNewTask.WaitOne(); + if (!_tasksQueue.IsEmpty) { - _waiterNewTask.WaitOne(); - if (!_tasksQueue.IsEmpty) - { - _waiterNewTask.Set(); - } + _waiterNewTask.Set(); } } + } - Interlocked.Increment(ref _freeThreadsCount); - _waiterTaskDone.Set(); - }); + Interlocked.Increment(ref _freeThreadsCount); + _waiterTaskDone.Set(); + }); - _threads[i].Start(); - } + _threads[i].Start(); } + } - /// - /// add task - /// - public IMyTask AddTask(Func function) + /// + /// add task + /// + public IMyTask AddTask(Func function) + { + ReadyToAddNewTask(); + lock (_lockObject) { ReadyToAddNewTask(); - lock (_lockObject) - { - if (_token.IsCancellationRequested) - { - throw new InvalidOperationException(); - } - var task = new MyTask(function, this); - AddInTaskQueue(task.Count); - return task; - } + var task = new MyTask(function, this); + AddInTaskQueue(task.Count); + return task; } + } - private void ReadyToAddNewTask() + private void ReadyToAddNewTask() + { + if (_token.IsCancellationRequested) { - if (_token.IsCancellationRequested) - { - throw new InvalidOperationException(); - } + throw new InvalidOperationException(); } + } - private void AddInTaskQueue(Action task) + private void AddInTaskQueue(Action task) + { + _tasksQueue.Enqueue(task); + _waiterNewTask.Set(); + } + + /// + /// close threads + /// + public void Shutdown() + { + lock (_lockObject) + { + _token.Cancel(); + } + + while (_freeThreadsCount != _threads.Length) { - _tasksQueue.Enqueue(task); _waiterNewTask.Set(); + _waiterTaskDone.WaitOne(); } + } + + /// + /// class for parallel tasks + /// + private class MyTask : IMyTask + { + private Func _func; + private TResult _result; + private Exception _resultException = null; + private readonly object _locker = new(); + private readonly ManualResetEvent _waiterManual = new(false); + private Queue _continueWithTasksQueue = new(); + private readonly MyThreadPool _myThreadPool; + + /// + /// shows whether the task is completed or not + /// + public bool IsCompleted { get; set; } /// - /// close threads + /// returns the result of the task /// - public void Shutdown() + public TResult Result { - lock (_lockObject) + get { - _token.Cancel(); - } + _waiterManual.WaitOne(); + if (_resultException != null) + { + throw new AggregateException(_resultException); + } - while (_freeThreadsCount != _threads.Length) - { - _waiterNewTask.Set(); - _waiterTaskDone.WaitOne(); - _waiterTaskDone.Reset(); + return _result; } } /// - /// class for parallel tasks + /// constructor /// - private class MyTask : IMyTask + public MyTask(Func function, MyThreadPool myThreadPool) { - private Func _func; - private TResult _result; - private Exception _resultException = null; - private readonly object _locker = new(); - private readonly ManualResetEvent _waiterManual = new(false); - private Queue _continueWithTasksQueue = new(); - private readonly MyThreadPool _myThreadPool; - - /// - /// shows whether the task is completed or not - /// - public bool IsCompleted { get; set; } - - /// - /// returns the result of the task - /// - public TResult Result - { - get - { - _waiterManual.WaitOne(); - if (_resultException != null) - { - throw new AggregateException(_resultException); - } + ArgumentNullException.ThrowIfNull(function); + _func = function; + _myThreadPool = myThreadPool; + } - return _result; - } + /// + /// counting result of task + /// + public void Count() + { + try + { + _result = _func(); } - - /// - /// constructor - /// - public MyTask(Func function, MyThreadPool myThreadPool) + catch (Exception funcException) { - _func = function ?? throw new ArgumentNullException(nameof(function)); - _myThreadPool = myThreadPool; + _resultException = funcException; } - /// - /// counting result of task - /// - public void Count() + lock (_locker) { - try - { - _result = _func(); - } - catch (Exception funcException) - { - _resultException = funcException; - } - - lock (_locker) - { - _func = null; - IsCompleted = true; - _waiterManual.Set(); - } + _func = null; + IsCompleted = true; + _waiterManual.Set(); + } - lock (_locker) + lock (_locker) + { + while (_continueWithTasksQueue.Count > 0) { - while (_continueWithTasksQueue.Count > 0) + var action = _continueWithTasksQueue.Dequeue(); + lock (_myThreadPool._lockObject) { - var action = _continueWithTasksQueue.Dequeue(); - lock (_myThreadPool._lockObject) - { - _myThreadPool.AddInTaskQueue(action); - } + _myThreadPool.AddInTaskQueue(action); } } } + } - /// - /// continues calculating - /// - public IMyTask ContinueWith(Func func) + /// + /// continues calculating + /// + public IMyTask ContinueWith(Func func) + { + lock (_myThreadPool._lockObject) { - lock (_myThreadPool._lockObject) + _myThreadPool.ReadyToAddNewTask(); + var task = new MyTask(() => func(Result), _myThreadPool); + _continueWithTasksQueue.Enqueue(task.Count); + if (IsCompleted) { - _myThreadPool.ReadyToAddNewTask(); - var task = new MyTask(() => func(Result), _myThreadPool); - _continueWithTasksQueue.Enqueue(task.Count); - if (IsCompleted) + while (_continueWithTasksQueue.Count > 0) { - while (_continueWithTasksQueue.Count > 0) - { - var action = _continueWithTasksQueue.Dequeue(); - _myThreadPool._tasksQueue.Enqueue(action); - _myThreadPool._waiterNewTask.Set(); - } + var action = _continueWithTasksQueue.Dequeue(); + _myThreadPool._tasksQueue.Enqueue(action); + _myThreadPool._waiterNewTask.Set(); } - return task; } + return task; } } } diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs index 9b93c4d..d115e1e 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -1,6 +1,5 @@ using System; using NUnit.Framework; -using ThreadPool; namespace ThreadPoolTest { From 07da886ad64dc6ff1d6ba7c43045407d5995bd46 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 14 Mar 2022 12:24:43 +0300 Subject: [PATCH 13/15] fix code and add test --- ThreadPool/ThreadPool/IMyTask.cs | 5 +- ThreadPool/ThreadPool/MyThreadPool.cs | 8 +-- ThreadPool/ThreadPool/ThreadPool.csproj | 2 + ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 51 +++++++++++++++++++ .../ThreadPoolTest/ThreadPoolTest.csproj | 2 + 5 files changed, 63 insertions(+), 5 deletions(-) diff --git a/ThreadPool/ThreadPool/IMyTask.cs b/ThreadPool/ThreadPool/IMyTask.cs index fd46cb0..6ee16d4 100644 --- a/ThreadPool/ThreadPool/IMyTask.cs +++ b/ThreadPool/ThreadPool/IMyTask.cs @@ -1,4 +1,6 @@ -using System; +namespace ThreadPool; + +using System; /// /// interface for object from MyThreadPool @@ -20,3 +22,4 @@ public interface IMyTask /// public IMyTask ContinueWith(Func func); } + diff --git a/ThreadPool/ThreadPool/MyThreadPool.cs b/ThreadPool/ThreadPool/MyThreadPool.cs index 0ae67c8..f22dac4 100644 --- a/ThreadPool/ThreadPool/MyThreadPool.cs +++ b/ThreadPool/ThreadPool/MyThreadPool.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections.Concurrent; +namespace ThreadPool; + using System.Collections.Generic; -using System.Linq; using System.Threading; -using System.Threading.Tasks; +using System.Collections.Concurrent; +using System; /// /// pool of threads that can be used to execute tasks diff --git a/ThreadPool/ThreadPool/ThreadPool.csproj b/ThreadPool/ThreadPool/ThreadPool.csproj index 1542bbf..6a038c2 100644 --- a/ThreadPool/ThreadPool/ThreadPool.csproj +++ b/ThreadPool/ThreadPool/ThreadPool.csproj @@ -3,6 +3,8 @@ net6.0 Windows + 10 + disable diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs index d115e1e..26923d8 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -1,5 +1,7 @@ using System; +using System.Threading; using NUnit.Framework; +using ThreadPool; namespace ThreadPoolTest { @@ -134,5 +136,54 @@ public void ContinueWithTest() Assert.AreEqual(16, task2.Result); Assert.AreEqual(28, task3.Result); } + + [Test] + public void TestWithSeveralThreads() + { + var answerFunc = 10000; + var countOfTasks = 15; + var tasks = new IMyTask[countOfTasks]; + var functions = new Func[countOfTasks]; + _threadPool = new MyThreadPool(5); + var threads = new Thread[10]; + for (int i = 0; i < 10; i++) + { + threads[i] = new Thread(() => + { + var threadTasks = new IMyTask[15]; + var threadFunctions = new Func[15]; + for (int j = 0; j < countOfTasks; j++) + { + var index = j; + threadFunctions[j] = new Func(() => + { + var result = 0; + for (int z = 0; z < answerFunc; z++) + { + result++; + } + + return result + index; + }); + } + + for (int j = 0; j < countOfTasks; j++) + { + threadTasks[j] = _threadPool.AddTask(functions[j]); + } + + for (int j = 0; j < countOfTasks; j++) + { + Assert.AreEqual(answerFunc + j, threadTasks[j].Result); + } + }); + } + + for (int i = 0; i < 10; i++) + { + threads[i].Start(); + threads[i].Join(); + } + } } } \ No newline at end of file diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj b/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj index a82263a..2ba879f 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.csproj @@ -4,6 +4,8 @@ net6.0 false + + 10 From 13d7c71d7db6cb7b08801498a6c02eb531c67cc5 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 14 Mar 2022 13:04:32 +0300 Subject: [PATCH 14/15] fix test --- ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs index 26923d8..57794f9 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -145,6 +145,25 @@ public void TestWithSeveralThreads() var tasks = new IMyTask[countOfTasks]; var functions = new Func[countOfTasks]; _threadPool = new MyThreadPool(5); + for (int i = 0; i < countOfTasks; i++) + { + var index = i; + functions[i] = new Func(() => + { + var result = 0; + for (int j = 0; j < answerFunc; j++) + { + result++; + } + + return result + index; + }); + } + + for (int i = 0; i < countOfTasks; i++) + { + tasks[i] = _threadPool.AddTask(functions[i]); + } var threads = new Thread[10]; for (int i = 0; i < 10; i++) { From 638fce6d8f7d4f2d4b5720582d156110f1cfee4c Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 14 Mar 2022 13:25:34 +0300 Subject: [PATCH 15/15] fix --- ThreadPool/ThreadPoolTest/ThreadPoolTest.cs | 323 ++++++++++---------- 1 file changed, 161 insertions(+), 162 deletions(-) diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs index 57794f9..33f916e 100644 --- a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs +++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs @@ -1,208 +1,207 @@ +namespace ThreadPoolTest; + using System; using System.Threading; using NUnit.Framework; using ThreadPool; -namespace ThreadPoolTest +public class Tests { - public class Tests - { - private MyThreadPool _threadPool; - private readonly int _numberOfThreads = 4; + private MyThreadPool _threadPool; + private readonly int _numberOfThreads = 4; - [SetUp] - public void Setup() - => _threadPool = new(Environment.ProcessorCount); + [SetUp] + public void Setup() + => _threadPool = new(Environment.ProcessorCount); - [TearDown] - public void TearDown() - => _threadPool.Shutdown(); + [TearDown] + public void TearDown() + => _threadPool.Shutdown(); - [Test] - public void NullFunctionShouldThrowException() - { - Assert.Throws(() => _threadPool.AddTask(null)); - } + [Test] + public void NullFunctionShouldThrowException() + { + Assert.Throws(() => _threadPool.AddTask(null)); + } - [Test] - public void ResultShouldThrowException() - { - var task = _threadPool.AddTask(() => throw new ArgumentOutOfRangeException()); - Assert.Throws(() => Result(task)); - } + [Test] + public void ResultShouldThrowException() + { + var task = _threadPool.AddTask(() => throw new ArgumentOutOfRangeException()); + Assert.Throws(() => Result(task)); + } - [Test] - public void ParallelAddTaskTest() + [Test] + public void ParallelAddTaskTest() + { + var tasks = new IMyTask[30]; + var functions = new Func[30]; + for (int i = 0; i < 30; i++) { - var tasks = new IMyTask[30]; - var functions = new Func[30]; - for (int i = 0; i < 30; i++) + var index = i; + functions[i] = () => { - var index = i; - functions[i] = () => + var result = 0; + for (int j = 0; j < 100; j++) { - var result = 0; - for (int j = 0; j < 100; j++) - { - result++; - } - return result + index; - }; - } - - for (int i = 0; i < 30; i++) - { - tasks[i] = _threadPool.AddTask(functions[i]); - } - for (int i = 0; i < 30; i++) - { - Assert.AreEqual(100 + i, tasks[i].Result); - } + result++; + } + return result + index; + }; } - [Test] - public void ShutdownWhileTaskCountTest() + for (int i = 0; i < 30; i++) { - var tasks = new IMyTask[30]; - var functions = new Func[30]; - for (int i = 0; i < 30; i++) - { - var i1 = i; - functions[i] = () => - { - var result = 0; - for (int j = 0; j < 10; j++) - { - result += 10; - } - return result + i1; - }; - } - - for (int i = 0; i < 30; i++) - { - tasks[i] = _threadPool.AddTask(functions[i]); - } - _threadPool.Shutdown(); - for (int i = 0; i < 30; i++) - { - Assert.AreEqual(100 + i, tasks[i].Result); - } + tasks[i] = _threadPool.AddTask(functions[i]); } - - private object Result(IMyTask task) - => task.Result; - - [Test] - public void ExceptionInThreadPoolConstructorTest() + for (int i = 0; i < 30; i++) { - Assert.Throws(() => new MyThreadPool(0)); + Assert.AreEqual(100 + i, tasks[i].Result); } + } - [Test] - public void ExceptionAfterShutdownTest() + [Test] + public void ShutdownWhileTaskCountTest() + { + var tasks = new IMyTask[30]; + var functions = new Func[30]; + for (int i = 0; i < 30; i++) { - _threadPool.Shutdown(); - Assert.Throws(() => _threadPool.AddTask(() => 5)); + var i1 = i; + functions[i] = () => + { + var result = 0; + for (int j = 0; j < 10; j++) + { + result += 10; + } + return result + i1; + }; } - [Test] - public void GetTaskAfterShutdown() + for (int i = 0; i < 30; i++) { - var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); - var task2 = _threadPool.AddTask(() => _numberOfThreads * _numberOfThreads); - Assert.AreEqual(12, task1.Result); - Assert.AreEqual(16, task2.Result); + tasks[i] = _threadPool.AddTask(functions[i]); } - - [Test] - public void TaskResultTest() + _threadPool.Shutdown(); + for (int i = 0; i < 30; i++) { - int number1 = 2; - int number2 = 2; - var task1 = _threadPool.AddTask(() => number1 + 2); - var task2 = _threadPool.AddTask(() => number2 * 5); - Assert.AreEqual(4, task1.Result); - Assert.AreEqual(10, task2.Result); + Assert.AreEqual(100 + i, tasks[i].Result); } + } + + private object Result(IMyTask task) + => task.Result; - [Test] - public void ContinueWithTest() - { - var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); //12 - var task2 = task1.ContinueWith(x => x + _numberOfThreads); //12 + 4 - var task3 = task1.ContinueWith(x => x + task2.Result); // 12 + 16 - Assert.AreEqual(12, task1.Result); - Assert.AreEqual(16, task2.Result); - Assert.AreEqual(28, task3.Result); - } + [Test] + public void ExceptionInThreadPoolConstructorTest() + { + Assert.Throws(() => new MyThreadPool(0)); + } + + [Test] + public void ExceptionAfterShutdownTest() + { + _threadPool.Shutdown(); + Assert.Throws(() => _threadPool.AddTask(() => 5)); + } + + [Test] + public void GetTaskAfterShutdown() + { + var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); + var task2 = _threadPool.AddTask(() => _numberOfThreads * _numberOfThreads); + Assert.AreEqual(12, task1.Result); + Assert.AreEqual(16, task2.Result); + } + + [Test] + public void TaskResultTest() + { + int number1 = 2; + int number2 = 2; + var task1 = _threadPool.AddTask(() => number1 + 2); + var task2 = _threadPool.AddTask(() => number2 * 5); + Assert.AreEqual(4, task1.Result); + Assert.AreEqual(10, task2.Result); + } + + [Test] + public void ContinueWithTest() + { + var task1 = _threadPool.AddTask(() => 3 * _numberOfThreads); //12 + var task2 = task1.ContinueWith(x => x + _numberOfThreads); //12 + 4 + var task3 = task1.ContinueWith(x => x + task2.Result); // 12 + 16 + Assert.AreEqual(12, task1.Result); + Assert.AreEqual(16, task2.Result); + Assert.AreEqual(28, task3.Result); + } - [Test] - public void TestWithSeveralThreads() + [Test] + public void TestWithSeveralThreads() + { + var answerFunc = 10000; + var countOfTasks = 15; + var tasks = new IMyTask[countOfTasks]; + var functions = new Func[countOfTasks]; + _threadPool = new MyThreadPool(5); + for (int i = 0; i < countOfTasks; i++) { - var answerFunc = 10000; - var countOfTasks = 15; - var tasks = new IMyTask[countOfTasks]; - var functions = new Func[countOfTasks]; - _threadPool = new MyThreadPool(5); - for (int i = 0; i < countOfTasks; i++) + var index = i; + functions[i] = new Func(() => { - var index = i; - functions[i] = new Func(() => + var result = 0; + for (int j = 0; j < answerFunc; j++) { - var result = 0; - for (int j = 0; j < answerFunc; j++) - { - result++; - } + result++; + } - return result + index; - }); - } + return result + index; + }); + } - for (int i = 0; i < countOfTasks; i++) - { - tasks[i] = _threadPool.AddTask(functions[i]); - } - var threads = new Thread[10]; - for (int i = 0; i < 10; i++) + for (int i = 0; i < countOfTasks; i++) + { + tasks[i] = _threadPool.AddTask(functions[i]); + } + var threads = new Thread[10]; + for (int i = 0; i < 10; i++) + { + threads[i] = new Thread(() => { - threads[i] = new Thread(() => + var threadTasks = new IMyTask[countOfTasks]; + var threadFunctions = new Func[countOfTasks]; + for (int j = 0; j < countOfTasks; j++) { - var threadTasks = new IMyTask[15]; - var threadFunctions = new Func[15]; - for (int j = 0; j < countOfTasks; j++) + var index = j; + threadFunctions[j] = new Func(() => { - var index = j; - threadFunctions[j] = new Func(() => + var result = 0; + for (int z = 0; z < answerFunc; z++) { - var result = 0; - for (int z = 0; z < answerFunc; z++) - { - result++; - } + result++; + } - return result + index; - }); - } + return result + index; + }); + } - for (int j = 0; j < countOfTasks; j++) - { - threadTasks[j] = _threadPool.AddTask(functions[j]); - } + for (int j = 0; j < countOfTasks; j++) + { + threadTasks[j] = _threadPool.AddTask(functions[j]); + } - for (int j = 0; j < countOfTasks; j++) - { - Assert.AreEqual(answerFunc + j, threadTasks[j].Result); - } - }); - } + for (int j = 0; j < countOfTasks; j++) + { + Assert.AreEqual(answerFunc + j, threadTasks[j].Result); + } + }); + } - for (int i = 0; i < 10; i++) - { - threads[i].Start(); - threads[i].Join(); - } + for (int i = 0; i < 10; i++) + { + threads[i].Start(); + threads[i].Join(); } } } \ No newline at end of file